2013-08-11 41 views
23

Tôi mới sử dụng đa xử lý bằng Python và cố gắng tìm hiểu xem tôi có nên sử dụng Pool hoặc Process để gọi hai hàm không đồng bộ. Hai hàm tôi đã thực hiện cuộc gọi curl và phân tích thông tin thành 2 danh sách riêng biệt. Tùy thuộc vào kết nối internet, mỗi chức năng có thể mất khoảng 4 giây. Tôi nhận thấy rằng nút cổ chai là trong kết nối ISP và đa xử lý sẽ không tăng tốc độ nó lên nhiều, nhưng nó sẽ là tốt đẹp để có cả hai đều khởi động async. Thêm vào đó, đây là một trải nghiệm học tập tuyệt vời cho tôi để bắt đầu với quá trình đa xử lý của python vì tôi sẽ sử dụng nó sau này.Xử lý đa xử lý Python hoặc Pool cho những gì tôi đang làm?

Tôi đã đọc Python multiprocessing.Pool: when to use apply, apply_async or map? và nó hữu ích, nhưng vẫn có câu hỏi của riêng tôi.

Vì vậy, một trong những cách tôi có thể làm điều đó là:

Câu hỏi tôi có thực hiện này là: 1) Kể từ khi gia nhập khối cho đến khi quá trình gọi là hoàn thành ... Điều này có nghĩa là quá trình p1 có để kết thúc trước khi quá trình p2 được khởi động? Tôi luôn hiểu hàm .join() giống như pool.apply() và pool.apply_sync(). Get() trong đó tiến trình cha không thể khởi chạy tiến trình (tác vụ) khác cho đến khi tiến trình đang chạy được hoàn thành.

Các lựa chọn khác sẽ là một cái gì đó như:

def foo(): 
    pass 

def bar(): 
    pass 
pool = Pool(processes=2)    
p1 = pool.apply_async(foo) 
p1 = pool.apply_async(bar) 

Câu hỏi tôi có thực hiện này sẽ là: 1) Tôi có cần một pool.close(), pool.join()? 2) Pool.map() có làm cho chúng hoàn chỉnh trước khi tôi có thể nhận được kết quả không? Và nếu vậy, họ vẫn chạy asynch? 3) Cách pool.apply_async() khác với việc thực hiện từng quy trình với pool.apply() 4) Điều này khác với cách thực hiện trước đó với Quy trình như thế nào?

Trả lời

22

Hai trường hợp bạn liệt kê hoàn thành giống nhau nhưng theo những cách hơi khác nhau.

Kịch bản đầu tiên bắt đầu hai quá trình riêng biệt (gọi chúng là P1 và P2) và bắt đầu P1 chạy foo và P2 chạy bar và đợi cho đến khi cả hai quá trình hoàn thành nhiệm vụ tương ứng.

Kịch bản thứ hai bắt đầu hai quy trình (gọi là Q1 và Q2) và bắt đầu đầu tiên foo vào Q1 hoặc Q2 và sau đó bắt đầu bar vào Q1 hoặc Q2. Sau đó, mã chờ cho đến khi cả hai cuộc gọi hàm đã trở lại.

Vì vậy, kết quả thực sự giống nhau, nhưng trong trường hợp đầu tiên, bạn được bảo đảm chạy foobar về các quy trình khác nhau. Đối với các câu hỏi cụ thể mà bạn có về đồng thời, phương pháp .join() trên Process thực sự chặn cho đến khi quá trình kết thúc, nhưng vì bạn gọi là .start() trên cả P1 và P2 (trong kịch bản đầu tiên) trước khi tham gia, sau đó cả hai quy trình sẽ chạy không đồng bộ. Tuy nhiên, thông dịch viên sẽ đợi cho đến khi P1 kết thúc trước khi cố gắng đợi P2 hoàn tất.

Đối với câu hỏi của bạn về kịch bản hồ bơi, bạn nên sử dụng kỹ thuật pool.close() nhưng nó phụ thuộc vào những gì bạn có thể cần sau này (nếu nó vượt quá phạm vi thì bạn không cần phải đóng nó).pool.map() là một loại động vật hoàn toàn khác, bởi vì nó phân phối một loạt các đối số cho cùng một hàm (không đồng bộ), qua các quy trình nhóm và đợi cho đến khi tất cả các cuộc gọi hàm đã hoàn tất trước khi trả về danh sách kết quả.

9

Vì bạn đang tìm nạp dữ liệu từ các cuộc gọi curl, bạn bị ràng buộc bởi IO. Trong trường hợp này, grequests có thể hữu ích. Đây thực sự không phải là các quy trình cũng như các chủ đề mà là các coroutines - các luồng nhẹ. Điều này sẽ cho phép bạn gửi các yêu cầu HTTP không đồng bộ và sau đó sử dụng multiprocessing.Pool để tăng tốc độ phần CPU bị ràng buộc.

1) Vì các khối kết nối cho đến khi quá trình gọi hoàn tất ... quá trình p1 có nghĩa là phải hoàn thành trước khi quá trình p2 được khởi động?

Có, p2.join() được gọi sau khi p1.join() đã trả lại có nghĩa là p1 đã hoàn tất.

1) Tôi có cần một pool.close(), pool.join()

Bạn có thể kết thúc với quá trình mồ côi mà không làm close()join() (nếu các quy trình phục vụ indefinetly)

2) Pool.map() có làm cho chúng hoàn chỉnh trước khi tôi có thể nhận được kết quả không? Và nếu vậy, họ vẫn chạy asynch?

Chúng được chạy không đồng bộ, nhưng map() bị chặn cho đến khi tất cả các tác vụ được thực hiện.

3) Làm thế nào sẽ pool.apply_async() khác với làm mỗi quá trình với pool.apply()

pool.apply() chặn, vì vậy về cơ bản bạn sẽ làm việc xử lý đồng bộ.

4) Làm thế nào điều này sẽ khác nhau từ việc thực hiện trước đó với Process

Rất có thể là một nhân viên được thực hiện với foo trước khi bạn áp dụng bar vì vậy bạn có thể kết thúc với một nhân viên độc thân làm tất cả công việc. Ngoài ra, nếu một trong các công nhân của bạn chết Pool sẽ tự động sinh ra một công cụ mới (bạn cần phải đăng ký lại tác vụ).

Để tổng hợp: Tôi thích sử dụng Pool - nó hoàn hảo cho các trường hợp người tiêu dùng sản xuất và quản lý tất cả logic phân phối tác vụ.

+1

Bạn có chắc chắn quá trình p1 phải hoàn tất trước khi quá trình p2 được khởi động vì tham gia() không? đầu ra từ http://bpaste.net/show/ruHgFTAAMkN4UT2INPqu/ trông giống như trên p2 kicks off trước khi p1 kết thúc. – dman

+2

Ý tôi là, 'p2' sẽ được nối sau khi' p1' được kết thúc. Xin lỗi vì sự hiểu nhầm. Tất nhiên, cả hai quá trình khởi động ngay khi 'start()' thích hợp đã trở lại. –

Các vấn đề liên quan