、map
の結果を破棄しないでください。 map
は、各関数から返された値を返すので、無視しただけです。このコードは、その意図された目的のためにmap
を使用することによって大幅に簡素化することができます
def f(n):
return n # No need to wrap in list
with ThreadPoolExecutor(max_workers=20) as exec:
master_list = list(exec.map(f, range(1, 100)))
print(master_list)
あなたがこれまでに計算された結果は、(おそらくいくつかの他のスレッドがそれを見ている)を示しmaster_list
が必要な場合は、あなただけのループを明示的に:
def f(n):
return n # No need to wrap in list
master_list = []
with ThreadPoolExecutor(max_workers=20) as exec:
for result in exec.map(f, range(1, 100)):
master_list.append(result)
print(master_list)
これはExecutorモデルのために設計されたものです。通常のスレッドは値を返すことを意図していませんが、エグゼキュータは、カバーの下の値を返すためのチャンネルを提供していますので、自分で管理する必要はありません。内部的には、これは何らかの形式のキューを使用しており、結果を順番に保持するためのメタデータを追加していますが、その複雑さに対処する必要はありません。あなたの見解では、それは通常のmap
関数に相当しますが、ちょうどその作業を並列化することになります。
更新は例外を扱うカバーする:結果がヒットしたとき
map
は、労働者に発生したすべての例外を発生させます。したがって、記述されているように、タスクのいずれかが失敗した場合、最初のコードセットは何も格納しません(list
は部分的に構築されますが、例外が発生すると破棄されます)。 2番目の例では、最初の例外がスローされる前に結果が保持され、残りは破棄されます(map
イテレータを格納し、それを避けるために厄介なコードを使用する必要があります)。成功したすべての結果を保存したり、何らかの方法でログに記録したりする必要がある場合は、submit
をlist
のFuture
というオブジェクトを作成するのが最も簡単なものにして、シリアルまたは完了の順番で待ちます(.result()
)。 try
/except
を呼び出して良い結果を捨てないようにします。例えば、提出の順に結果を格納するために、あなたがしたい:より効率的なコードの場合
master_list = []
with ThreadPoolExecutor(max_workers=20) as exec:
futures = [exec.submit(f, i) for i in range(1, 100)]
exec.shutdown(False) # Optional: workers terminate as soon as all futures finish,
# rather than waiting for all results to be processed
for fut in futures:
try:
master_list.append(fut.result())
except Exception:
... log error here ...
、あなたは彼らが終了して熱心に結果を取得するためにconcurrent.futures.as_completed
を使用して、完了の順に結果ではなく、提出を取得することができます。
for fut in futures:
は次のようになります:
as_completed
は、すぐにすべての先物まで、彼らは完全に、代わりの遅延など
yield
ING完了/キャンセル先物の作業を行い
for fut in concurrent.futures.as_completed(futures):
前のコードからの唯一の変更は、ということです早期に提出され、処理されます。
add_done_callback
を使用するより複雑なオプションがありますので、メインスレッドは結果を明示的に処理する必要はありませんが、通常は不要で、しばしば混乱するので、可能な限り避けるのが最善です。
+1素晴らしい情報を共有します。私は疑問が1つありました。渡された関数によって例外が発生した場合、どのように動作しますか?それはそれを処理しますか? –
@Moinuddin私の経験では、 'map'の代わりにThreadPoolExcecutorsを使ってエラー処理を行うには、' submit'を使います。これは未来を返し、それが完了した後に 'future.result()'を呼び出します。これにより、キャッチされた例外が発生します。 – flybonzai
@flybonai:Yar。 'Future'の' list'を作成し、結果の順序が重要であれば、 'list'を繰り返し実行して、' try'/'except'をラップして順次実行します)。結果の順序が重要でない場合、 '' concurrent.futures.as_completed''(https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.as_completed)を使用すると '未来 "のオブジェクトは終了する(正常にまたは例外のために)。再び、 'try' /' except'ブロックで 'result'を呼び出してエラーを処理します。後者は、重要でない場合は一般に効率的です。 – ShadowRanger