đa xử lý.Pool: Khi nào sử dụng áp dụng, áp dụng_async hoặc bản đồ?


Câu trả lời:


424

Quay lại thời kỳ cũ của Python, để gọi một hàm với các đối số tùy ý, bạn sẽ sử dụng apply:

apply(f,args,kwargs)

applyvẫn tồn tại trong Python2.7 mặc dù không có trong Python3 và thường không được sử dụng nữa. Ngày nay,

f(*args,**kwargs)

được ưa thích. Các multiprocessing.Poolmô-đun cố gắng cung cấp một giao diện tương tự.

Pool.applygiống như Python apply, ngoại trừ việc gọi hàm được thực hiện trong một quy trình riêng. Pool.applykhối cho đến khi chức năng được hoàn thành.

Pool.apply_asynccũng giống như tích hợp sẵn của Python apply, ngoại trừ việc cuộc gọi trả về ngay lập tức thay vì chờ kết quả. Một AsyncResultđối tượng được trả lại. Bạn gọi get()phương thức của nó để lấy kết quả của hàm gọi. Các get()phương thức chặn cho đến khi chức năng được hoàn thành. Như vậy, pool.apply(func, args, kwargs)tương đương với pool.apply_async(func, args, kwargs).get().

Ngược lại Pool.apply, Pool.apply_asyncphương thức cũng có một cuộc gọi lại, nếu được cung cấp, được gọi khi hàm hoàn thành. Điều này có thể được sử dụng thay vì gọi get().

Ví dụ:

import multiprocessing as mp
import time

def foo_pool(x):
    time.sleep(2)
    return x*x

result_list = []
def log_result(result):
    # This is called whenever foo_pool(i) returns a result.
    # result_list is modified only by the main process, not the pool workers.
    result_list.append(result)

def apply_async_with_callback():
    pool = mp.Pool()
    for i in range(10):
        pool.apply_async(foo_pool, args = (i, ), callback = log_result)
    pool.close()
    pool.join()
    print(result_list)

if __name__ == '__main__':
    apply_async_with_callback()

có thể mang lại một kết quả như

[1, 0, 4, 9, 25, 16, 49, 36, 81, 64]

Lưu ý, không giống như pool.map, thứ tự của các kết quả có thể không tương ứng với thứ tự mà các pool.apply_asynccuộc gọi được thực hiện.


Vì vậy, nếu bạn cần chạy một hàm trong một quy trình riêng biệt, nhưng muốn quy trình hiện tại bị chặn cho đến khi chức năng đó trở lại, hãy sử dụng Pool.apply. Giống như Pool.apply, Pool.mapkhối cho đến khi kết quả hoàn thành được trả về.

Nếu bạn muốn nhóm quy trình worker thực hiện nhiều lệnh gọi không đồng bộ, hãy sử dụng Pool.apply_async. Thứ tự của các kết quả không được đảm bảo giống như thứ tự của các cuộc gọi đến Pool.apply_async.

Cũng lưu ý rằng bạn có thể gọi một số chức năng khác nhauPool.apply_async (không phải tất cả các cuộc gọi đều cần sử dụng cùng một chức năng).

Ngược lại, Pool.mapáp dụng cùng chức năng cho nhiều đối số. Tuy nhiên, không giống như Pool.apply_async, các kết quả được trả về theo thứ tự tương ứng với thứ tự của các đối số.


11
Có nên có if __name__=="__main__"trước apply_async_with_callback()trên Windows?
jfs

3
Cảm ơn rất nhiều. làm thế nào về map_async?
Phyo Arkar Lwin

38
Nhìn vào bên trong đa xử lý / pool.py và bạn sẽ thấy điều đó Pool.map(func,iterable)tương đương với Pool.map_async(func,iterable).get(). Vì vậy, mối quan hệ giữa Pool.mapPool.map_asynctương tự như Pool.applyPool.apply_async. Các asynclệnh trả về ngay lập tức, trong khi khối không asynclệnh. Các asynclệnh cũng có một cuộc gọi lại.
unutbu

7
Quyết định giữa việc sử dụng Pool.mapPool.applytương tự như quyết định khi nào nên sử dụng maphoặc applytrong Python. Bạn chỉ cần sử dụng công cụ phù hợp với công việc. Quyết định giữa việc sử dụng phiên bản asyncvà không asyncphiên bản tùy thuộc vào việc bạn có muốn cuộc gọi chặn quy trình hiện tại và / hoặc nếu bạn muốn sử dụng cuộc gọi lại.
unutbu

6
@falsePockets: Có. Mỗi cuộc gọi để apply_asynctrả về một ApplyResultđối tượng. Gọi đó ApplyResultgetphương pháp sẽ trở lại giá trị trả về các chức năng liên quan (hoặc tăng lương mp.TimeoutErrornếu cuộc gọi lần-out.) Vì vậy, nếu bạn đặt các ApplyResults trong một danh sách đặt hàng, sau đó kêu gọi họ getphương pháp này sẽ trả lại kết quả theo thứ tự. Bạn chỉ có thể sử dụng pool.maptrong tình huống này.
unutbu

75

Về applyvs map:

pool.apply(f, args): fchỉ được thực hiện trong MỘT trong số các công nhân của nhóm. Vì vậy, MỘT trong các quy trình trong nhóm sẽ chạy f(args).

pool.map(f, iterable): Phương thức này chia iterable thành một số khối mà nó gửi đến nhóm quy trình dưới dạng các tác vụ riêng biệt. Vì vậy, bạn tận dụng tất cả các quy trình trong nhóm.


4
Điều gì xảy ra nếu iterable là một máy phát điện
RustyShackleford

Hmm ... Câu hỏi hay. Thành thật mà nói tôi chưa từng sử dụng hồ bơi với máy phát điện, nhưng chủ đề này có thể hữu ích: stackoverflow.com/questions/5318936/
mẹo

@kakhkAtion Về việc áp dụng, nếu chỉ một trong số các công nhân thực hiện chức năng, những công nhân còn lại sẽ làm gì? Tôi có phải gọi áp dụng nhiều lần để các công nhân còn lại thực hiện một nhiệm vụ không?
Moondra

3
Thật. Ngoài ra, hãy xem pool.apply_async nếu bạn muốn nhân viên ăn trưa không đồng bộ. "pool_apply chặn cho đến khi kết quả sẵn sàng, vì vậy áp dụng_async () phù hợp hơn để thực hiện công việc song song"
kakhkAtion

1
Điều gì xảy ra khi tôi có 4 quy trình nhưng đã gọi apply_async()8 lần? Nó sẽ tự động xử lý nó với một hàng đợi?
Saravanabalagi Ramachandran

31

Dưới đây là một cái nhìn tổng quan trong một định dạng bảng để hiển thị sự khác nhau giữa Pool.apply, Pool.apply_async, Pool.mapPool.map_async. Khi chọn một, bạn phải đưa nhiều đối số, đồng thời, chặn và đặt hàng vào tài khoản:

                  | Multi-args   Concurrence    Blocking     Ordered-results
---------------------------------------------------------------------
Pool.map          | no           yes            yes          yes
Pool.map_async    | no           yes            no           yes
Pool.apply        | yes          no             yes          no
Pool.apply_async  | yes          yes            no           no
Pool.starmap      | yes          yes            yes          yes
Pool.starmap_async| yes          yes            no           no

Ghi chú:

  • Pool.imapPool.imap_async- phiên bản lười hơn của bản đồ và map_async.

  • Pool.starmap phương thức, rất giống với phương thức ánh xạ bên cạnh việc chấp nhận nhiều đối số.

  • Asyncphương thức gửi tất cả các quy trình cùng một lúc và lấy kết quả sau khi hoàn thành. Sử dụng phương pháp get để có được kết quả.

  • Pool.map(hoặc Pool.apply) các phương thức rất giống với bản đồ dựng sẵn của Python (hoặc áp dụng). Họ chặn quy trình chính cho đến khi tất cả các quy trình hoàn thành và trả về kết quả.

Ví dụ:

bản đồ

Được gọi cho một danh sách các công việc trong một lần

results = pool.map(func, [1, 2, 3])

ứng dụng

Chỉ có thể được gọi cho một công việc

for x, y in [[1, 1], [2, 2]]:
    results.append(pool.apply(func, (x, y)))

def collect_result(result):
    results.append(result)

map_async

Được gọi cho một danh sách các công việc trong một lần

pool.map_async(func, jobs, callback=collect_result)

áp dụng_async

Chỉ có thể được gọi cho một công việc và thực hiện một công việc trong nền song song

for x, y in [[1, 1], [2, 2]]:
    pool.apply_async(worker, (x, y), callback=collect_result)

starmap

Là một biến thể trong pool.mapđó hỗ trợ nhiều đối số

pool.starmap(func, [(1, 1), (2, 1), (3, 1)])

starmap_async

Một sự kết hợp của starmap () và map_async () lặp đi lặp lại qua các lần lặp của các lần lặp và gọi func với các lần lặp được giải nén. Trả về một đối tượng kết quả.

pool.starmap_async(calculate_worker, [(1, 1), (2, 1), (3, 1)], callback=collect_result)

Tài liệu tham khảo:

Tìm tài liệu đầy đủ tại đây: https://docs.python.org/3/l Library / multiprocessing.html


2
Pool.starmap () đang chặn
Alan Evangelista
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.