imap
/imap_unordered
とmap
/には 2 つの重要な違いがありますmap_async
。
- 彼らがあなたが彼らに渡すイテラブルを消費する方法。
- 彼らが結果をあなたに返す方法。
map
iterable をリストに変換し (まだリストではない場合)、それをチャンクに分割し、それらのチャンクをPool
. イテラブルをチャンクに分割すると、特にイテラブルが大きい場合に、プロセス間でイテラブル内の各アイテムを一度に 1 アイテムずつ渡すよりもパフォーマンスが向上します。ただし、イテラブルをチャンク化するためにリストに変換すると、リスト全体をメモリに保持する必要があるため、メモリ コストが非常に高くなる可能性があります。
imap
与えられた iterable をリストに変換したり、チャンクに分割したりしません (デフォルト)。一度に反復可能な 1 つの要素を反復処理し、それぞれをワーカー プロセスに送信します。これは、イテラブル全体をリストに変換することによるメモリ ヒットが発生しないことを意味しますが、チャンキングがないため、大きなイテラブルのパフォーマンスが低下することも意味します。chunksize
ただし、これはデフォルトの 1 より大きい引数を渡すことで軽減できます。
imap
/imap_unordered
とmap
/のもう 1 つの大きな違いは、map_async
/ をimap
使用imap_unordered
すると、すべてのワーカーが終了するのを待つのではなく、準備ができたらすぐにワーカーから結果を受け取り始めることができることです。ではmap_async
、AsyncResult
がすぐに返されますが、すべてのオブジェクトが処理されるまで、そのオブジェクトから実際に結果を取得することはできません。その時点で、map
(map
は実際には として内部的に実装されていますmap_async(...).get()
) と同じリストを返します。部分的な結果を取得する方法はありません。結果全体が得られるか、何も得られないかのいずれかです。
imap
imap_unordered
どちらもイテラブルをすぐに返します。を使用imap
すると、入力イテラブルの順序を維持しながら、準備が整うとすぐに結果がイテラブルから生成されます。を使用imap_unordered
すると、入力イテラブルの順序に関係なく、準備が整うとすぐに結果が得られます。だから、あなたがこれを持っているとしましょう:
import multiprocessing
import time
def func(x):
time.sleep(x)
return x + 2
if __name__ == "__main__":
p = multiprocessing.Pool()
start = time.time()
for x in p.imap(func, [1,5,3]):
print("{} (Time elapsed: {}s)".format(x, int(time.time() - start)))
これは出力されます:
3 (Time elapsed: 1s)
7 (Time elapsed: 5s)
5 (Time elapsed: 5s)
p.imap_unordered
の代わりに使用すると、次のようにp.imap
表示されます。
3 (Time elapsed: 1s)
5 (Time elapsed: 3s)
7 (Time elapsed: 5s)
p.map
またはを使用するとp.map_async().get()
、次のように表示されます。
3 (Time elapsed: 5s)
7 (Time elapsed: 5s)
5 (Time elapsed: 5s)
imap
したがって、 / imap_unordered
overを使用する主な理由は次のmap_async
とおりです。
- イテラブルが十分に大きいため、リストに変換するとメモリが不足したり、メモリを使いすぎたりします。
- すべての結果が完了する前に、結果の処理を開始できるようにしたいと考えています。