Есть два ключевых различия между imap/ imap_unorderedи map/ map_async:
- То, как они потребляют итеративное, вы передаете им.
- То, как они возвращают результат обратно к вам.
mapпотребляет вашу итерируемую, преобразовывая итерируемую в список (предполагая, что это уже не список), разбивая его на порции и отправляя эти порции рабочим процессам в Pool. Разбиение итерируемого на куски работает лучше, чем передача каждого элемента в итерируемом между процессами по одному элементу за раз - особенно если итерация велика. Однако, превращение итерируемого в список для того, чтобы разделить его на части, может иметь очень высокую стоимость памяти, так как весь список должен храниться в памяти.
imapне превращает итерируемое вами в список и не разбивает его на куски (по умолчанию). Он будет перебирать итерируемый по одному элементу за раз и отправлять каждый из них в рабочий процесс. Это означает, что вы не берете на себя удар памяти при преобразовании всего итерируемого в список, но это также означает, что производительность для больших итераций ниже из-за отсутствия разбиения на фрагменты. Однако это можно уменьшить, передав chunksizeаргумент, больший, чем значение по умолчанию, равное 1.
Другое существенное отличие между imap/ imap_unorderedи map/ 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более map_async:
- Ваша итерация достаточно велика, поэтому ее преобразование в список может привести к нехватке / использованию слишком большого количества памяти.
- Вы хотите иметь возможность начать обработку результатов до того, как все они будут завершены.