[解決済み] ThreadPoolExecutor().mapとThreadPoolExecutor().submitはどう違うのですか?
質問
私は自分が書いたあるコードにとても困惑していました。私はそれを発見して驚きました。
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
results = list(executor.map(f, iterable))
と
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
results = list(map(lambda x: executor.submit(f, x), iterable))
は異なる結果を生成します。最初のものは、どんな型のリストであっても
f
が返すリストを生成し、2番目は
concurrent.futures.Future
オブジェクトのリストを生成し、それを
result()
メソッドで評価する必要があります。
f
が返した値を取得するためです。
私の主な懸念は、これがつまり
executor.map
を利用することができないということです。
concurrent.futures.as_completed
を利用することができません。これは、データベースへの長期にわたる呼び出しの結果が利用可能になったときに、その結果を評価するための非常に便利な方法のように思えます。
私は、どのように
concurrent.futures.ThreadPoolExecutor
オブジェクトがどのように機能するのか、全く理解していません。素朴に、私は (多少冗長な) 方がいいと思います。
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
result_futures = list(map(lambda x: executor.submit(f, x), iterable))
results = [f.result() for f in futures.as_completed(result_futures)]
より簡潔な
executor.map
を使うことで、パフォーマンスが向上する可能性があります。私はそうすることが間違っているのでしょうか?
どのように解決するのですか?
の結果を変換するのが問題です。
ThreadPoolExecutor.map
の結果をリストに変換していることです。これを行わず、結果のジェネレータを直接反復処理すると、結果は元の順序のまま得られますが、すべての結果が準備できる前にループが続行されます。この例でテストすることができます。
import time
import concurrent.futures
e = concurrent.futures.ThreadPoolExecutor(4)
s = range(10)
for i in e.map(time.sleep, s):
print(i)
順番が維持される理由は、マップに与えた順番と同じ順番で結果を得ることが重要な場合があるからでしょう。そして、結果はおそらく未来オブジェクトにラップされません。なぜなら、状況によっては、すべての結果を得るためにリストに対して別のマップを実行するには時間がかかりすぎるからです。そして、ほとんどの場合、ループが最初の値を処理する前に次の値が用意されている可能性が高いのです。これはこの例で実証されています。
import concurrent.futures
executor = concurrent.futures.ThreadPoolExecutor() # Or ProcessPoolExecutor
data = some_huge_list()
results = executor.map(crunch_number, data)
finals = []
for value in results:
finals.append(do_some_stuff(value))
この例では、おそらく
do_some_stuff
よりも時間がかかるかもしれません。
crunch_number
であり、これが本当にそうであるならば、マップの簡単な使い方を維持したまま、パフォーマンスの大きな損失にはなりません。
また、ワーカスレッド(/processes)はリストの先頭から処理を開始し、提出されたリストの末尾に向かうので、結果はすでにイテレータによってもたらされた順番に終了するはずです。つまり、ほとんどの場合
executor.map
はちょうどいいのですが、 場合によっては、例えばどの順番で値を処理するかは重要でなく
map
に渡した関数が実行されるまでにかかる時間が大きく異なる場合などには
future.as_completed
の方が速いかもしれません。
関連
-
[解決済み] 他のスレッドからGUIを更新するにはどうすればよいですか?
-
[解決済み] 列の値に基づいてDataFrameから行を選択するにはどうすればよいですか?
-
[解決済み] Pythonの辞書からキーを削除するにはどうしたらいいですか?
-
[解決済み] リストからランダムに項目を選択するにはどうすればよいですか?
-
[解決済み] C++11では、標準化されたメモリモデルが導入されました。その意味するところは?そして、C++プログラミングにどのような影響を与えるのでしょうか?
-
[解決済み] インデックスを指定してリストから要素を削除する方法
-
[解決済み] Pythonの@propertyデコレーターはどのように機能するのでしょうか?
-
[解決済み] Pythonのsuper()は多重継承でどう動くのか?
-
[解決済み】map関数を理解する
-
[解決済み] Pandasのデータフレームでタプルの列を分割するにはどうしたらいいですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Pandasのデータフレームでタプルの列を分割するにはどうしたらいいですか?
-
[解決済み] Pythonの構文に新しいステートメントを追加することはできますか?
-
[解決済み] PILからopenCVフォーマットへの変換
-
[解決済み] バブルソートの宿題
-
[解決済み] Spyderを仮想環境で動作させるには?
-
[解決済み] 文字列のリストを内容に基づいてフィルタリングする
-
[解決済み] python-requests モジュールからのすべてのリクエストをログに記録します。
-
[解決済み] Celeryタスクのユニットテストはどのように行うのですか?
-
[解決済み] PythonのRequestsモジュールを使ってWebサイトに "ログイン "するには?
-
[解決済み] Python の sorted() はどのようなアルゴリズムを使っているのですか?重複