Có hai điểm khác biệt chính giữa imap
/ imap_unordered
và map
/ map_async
:
- Cách họ tiêu thụ lặp đi lặp lại bạn truyền cho họ.
- Cách họ trả lại kết quả cho bạn.
map
tiêu thụ iterable của bạn bằng cách chuyển đổi iterable thành một danh sách (giả sử nó chưa phải là một danh sách), chia nó thành các khối và gửi các khối đó đến các quy trình worker trong Pool
. Việc chia iterable thành các khối thực hiện tốt hơn so với việc chuyển từng mục trong lần lặp giữa các tiến trình một mục tại một thời điểm - đặc biệt nếu số lần lặp lớn. Tuy nhiên, biến iterable thành một danh sách để chunk nó có thể có chi phí bộ nhớ rất cao, vì toàn bộ danh sách sẽ cần phải được giữ trong bộ nhớ.
imap
không biến iterable mà bạn đưa nó thành một danh sách, cũng không biến nó thành các khối (theo mặc định). Nó sẽ lặp đi lặp lại qua từng phần tử lặp và gửi chúng cho mỗi phần tử tới một quy trình worker. Điều này có nghĩa là bạn không sử dụng bộ nhớ để chuyển đổi toàn bộ lần lặp thành một danh sách, nhưng điều đó cũng có nghĩa là hiệu suất chậm hơn đối với các lần lặp lớn, vì thiếu đoạn mã. Điều này có thể được giảm thiểu bằng cách chuyển một chunksize
đối số lớn hơn mặc định là 1, tuy nhiên.
Sự khác biệt lớn khác giữa imap
/ imap_unordered
và map
/ map_async
, là với imap
/ imap_unordered
, bạn có thể bắt đầu nhận kết quả từ nhân viên ngay khi họ sẵn sàng, thay vì phải đợi tất cả trong số họ kết thúc. Với map_async
, một AsyncResult
trả về ngay lập tức, nhưng bạn thực sự không thể lấy kết quả từ đối tượng đó cho đến khi tất cả chúng được xử lý, tại đó nó trả về cùng một danh sách map
( map
thực tế được thực hiện như trong map_async(...).get()
). Không có cách nào để có được kết quả một phần; bạn có toàn bộ kết quả, hoặc không có gì.
imap
và imap_unordered
cả hai trả lại iterables ngay lập tức. Với imap
, kết quả sẽ được mang lại từ lần lặp ngay khi chúng sẵn sàng, trong khi vẫn duy trì thứ tự của lần lặp đầu vào. Với imap_unordered
, kết quả sẽ được mang lại ngay khi chúng sẵn sàng, bất kể thứ tự lặp lại đầu vào. Vì vậy, nói rằng bạn có điều này:
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)))
Điều này sẽ xuất ra:
3 (Time elapsed: 1s)
7 (Time elapsed: 5s)
5 (Time elapsed: 5s)
Nếu bạn sử dụng p.imap_unordered
thay vì p.imap
, bạn sẽ thấy:
3 (Time elapsed: 1s)
5 (Time elapsed: 3s)
7 (Time elapsed: 5s)
Nếu bạn sử dụng p.map
hoặc p.map_async().get()
, bạn sẽ thấy:
3 (Time elapsed: 5s)
7 (Time elapsed: 5s)
5 (Time elapsed: 5s)
Vì vậy, lý do chính để sử dụng imap
/ imap_unordered
hơn map_async
là:
- Lặp lại của bạn đủ lớn để chuyển đổi nó thành một danh sách sẽ khiến bạn hết / sử dụng quá nhiều bộ nhớ.
- Bạn muốn có thể bắt đầu xử lý kết quả trước khi hoàn thành tất cả chúng.