3

Python が初めてで、マルチスレッドを理解しようとしています。Queueに関する Python ドキュメントの例を次に示します。

私の人生の中で、この例がどのように機能するのか理解できません。worker() 関数には、無限ループがあります。従業員はループから抜け出すタイミングをどのように知るのでしょうか? 割れ具合はないようです。

そして、結合は最後に何をしているのでしょうか? 代わりにスレッドに参加するべきではありませんか?

def worker():
    while True:
        item = q.get()
        do_work(item)
        q.task_done()

q = Queue()
for i in range(num_worker_threads):
    t = Thread(target=worker)
    t.daemon = True
    t.start()

for item in source():
    q.put(item)

q.join()       # block until all tasks are done

また、別の質問です。いつマルチスレッドを使用する必要があり、いつマルチプロセッシングを使用する必要がありますか?

4

3 に答える 3

6

うん。あなたが正しい。worker永久に実行されます。ただし、キューには有限数のアイテムしかないため、最終的にworkerは永久にブロックされq.get()ます (キューにアイテムがなくなるため)。この時点で、workerまだ実行されていることは重要ではありません。q.join()Queue カウントが 0 になるまでブロックします (ワーカー スレッドが を呼び出すたびq.task_doneに、カウントは 1 ずつ減少します)。その後、プログラムは終了します。そして、無限にブロックしているスレッドは、その作成者と共に消滅します。

于 2012-07-23T21:07:14.357 に答える
5

2 番目の質問に関して、Python のスレッドとプロセスの最大の違いは、主流の実装ではグローバル インタープリター ロック (GIL) を使用して、複数のスレッドが Python の内部データ構造を台無しにできないようにすることです。これは、ほとんどの時間を純粋な Python での計算に費やすプログラムの場合、複数の CPU を使用しても、一度に 1 つのスレッドしか GIL を保持できないため、プログラムの速度はあまり向上しないことを意味します。一方、複数のスレッドが Python プログラム内で簡単にデータを共有でき、場合によっては (すべてではありませんが)、スレッドの安全性についてあまり心配する必要はありません。

マルチスレッドが Python プログラムを高速化できるのは、プログラムがほとんどの時間を I/O (ディスク アクセス、または最近では特にネットワーク操作) の待機に費やしている場合です。I/O を実行している間は GIL が保持されないため、I/O バウンドのアプリケーションで多くの Python スレッドを同時に実行できます。

一方、マルチプロセッシングでは、各プロセスに独自の GIL があるため、使用可能な CPU コアの数に応じてパフォーマンスをスケーリングできます。欠点は、プロセス間のすべての通信が multiprocessing.Queue を介して行われる必要があることです (表面上は Queue.Queue と非常によく似ていますが、プロセスの境界を越えて通信する必要があるため、根本的なメカニズムが大きく異なります)。

スレッド セーフまたはインタープロセス キューを介して作業することで、多くの潜在的なスレッド化の問題が回避され、Python ではそれが非常に簡単になるため、このmultiprocessingモジュールは非常に魅力的です。

于 2012-07-23T21:19:31.160 に答える
0

ほとんどの場合、joel-cornett に同意します。python2.7 で次のスニペットを実行しようとしました:

from threading import Thread
from Queue import Queue

def worker():
    def do_work(item):
        print(item)

    while True:
        item = q.get()
        do_work(item)
        q.task_done()

q = Queue()
for i in range(4):
     t = Thread(target=worker)
     t.daemon = True
     t.start()

for item in range(10):
    q.put(item)

q.join()

出力は次のとおりです。

0
1
2
3
4
5
6
7
8
9
Exception in thread Thread-3 (most likely raised during interpreter shutdown):
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 551, in __bootstrap_inner
  File "/usr/lib/python2.7/threading.py", line 504, in run
  File "abc.py", line 9, in worker
  File "/usr/lib/python2.7/Queue.py", line 168, in get
  File "/usr/lib/python2.7/threading.py", line 236, in wait
<type 'exceptions.TypeError'>: 'NoneType' object is not callable

私が考える最も可能性の高い説明:

タスクが使い果たされた後にキューが空になると、親スレッドは q.join() から戻った後に終了し、キューを破棄します。子スレッドは、「item = q.get()」で生成された最初の TypeError 例外を受け取ると終了します。これは、キューが存在しないためです。

于 2012-07-23T21:34:33.220 に答える