あなたの主な質問について:
これよりも複雑なことを行っている場合、または特にこれを繰り返し行っている場合は、おそらく「スレッド グループ」クラスが必要です。事前に作成されたものは数十ありますが、どれも気に入らない場合は、自分で作成するのは簡単です。
次に、これの代わりに:
threadList = []
for argchunk in splitIntoChunks(values, 10):
threadList.append(threading.Thread(target=myThreadFunc, args=argchunk))
...
someTotal = 0
for th in threadList:
th.join()
someTotal += th.resultsAttribute
あなたはこれを行うことができます:
threadGroup = ThreadGroup.ThreadGroup()
for argchunk in splitIntoChunks(values, 10):
threadGroup.newThread(myThreadFunc, argchunk)
threadGroup.join()
someTotal = sum(th.resultsAttribute for th in threadGroup)
または、もっと良いのは、完全なスレッド プール ライブラリです。これを行うことができます。
pool = ThreadPool(10)
for argchunk in splitIntoChunks(values, 100):
pool.putRequest(myThreadFunc, argchunk)
pool.wait()
ここでの利点は、スレッドごとに 10 個のジョブを 1 つずつスケジュールする代わりに、10 個のスレッドで 100 個のジョブを適切にスケジュールするのと同じくらい簡単にできることです。キューを維持するなどのすべての作業を行う必要はありません。欠点は、スレッドを反復処理できないことです。戻り値を取得するには、ジョブを反復する必要があります。理想的には、ジョブを反復できるようにするためだけに、ジョブを最後まで存続させたくありません。
これは、スレッド (またはジョブ) から値を取得する方法という 2 番目の質問につながります。これを行う方法はたくさんあります。
あなたがしたことはうまくいきます。ロックする必要さえありません。
あなたが提案したように、コールバックを使用することも機能します。ただし、コールバックはメイン スレッドではなくワーカー スレッドで実行されることに注意してください。そのため、何らかのグローバル オブジェクトにアクセスする場合は、何らかの同期が必要になります。
とにかく同期する場合は、コールバックにメリットがない可能性があります。たとえば、一連の値を合計するだけの場合は、 を設定するだけtotal=[0]
で、各スレッドtotal[0] += myValue
がロック内で実行できます。(もちろん、この場合、メイン スレッドで合計を実行してロックを回避する方が理にかなっている可能性がありますが、結果を結合する作業がはるかに重い場合、その選択はそれほど単純ではない可能性があります。)
明示的にロックする代わりに、ある種のアトミック オブジェクトを使用することもできます。たとえば、標準の Queue.Queue と collections.deque はどちらもアトミックであるため、各スレッドは を設定するだけq = Queue.Queue()
で、各スレッドは を実行して結果をプッシュし、q.push(myValue)
結合後は反復してキューの値を合計します。
group.join()
実際、各スレッドがキューに正確に 1 回プッシュする場合、キュー自体で 10 回のブロッキング取得を実行できます。その後、またはpool.wait()
または何かがすぐに返されることがわかります。
または、コールバックをジョブとしてキューにプッシュすることもできます。ここでも、キューで 10 回のブロッキング取得を実行し、そのたびに結果を実行できます。
各スレッドが複数のオブジェクトを返すことができる場合、処理が完了したときにセンチネル値またはコールバックをキューにプッシュでき、メイン スレッドは 10 個のセンチネルを読み取るまでポップし続けます。