multiprocessing vs multithreading vs asyncio trong Python 3


108

Tôi thấy rằng trong Python 3.4 có một vài thư viện khác nhau cho đa xử lý / luồng: đa xử lý so với luồngasyncio .

Nhưng tôi không biết cái nào để sử dụng hoặc là "một trong những khuyến nghị". Họ làm điều giống nhau hay khác nhau? Nếu vậy, cái nào được sử dụng để làm gì? Tôi muốn viết một chương trình sử dụng đa lõi trong máy tính của mình. Nhưng tôi không biết mình nên học ở thư viện nào.


Câu trả lời:


81

Chúng dành cho (một chút) các mục đích và / hoặc yêu cầu khác nhau. CPython (một triển khai Python dòng chính, điển hình) vẫn có khóa thông dịch toàn cục nên một ứng dụng đa luồng (một cách tiêu chuẩn để thực hiện xử lý song song ngày nay) là không tối ưu. Đó là lý do tại sao multiprocessing có thể được ưa thích hơn threading. Nhưng không phải mọi vấn đề đều có thể được chia thành các phần [gần như độc lập] một cách hiệu quả, vì vậy có thể cần phải có giao tiếp liên quy trình lớn. Đó là lý do tại sao multiprocessingcó thể không được ưa thích hơn threadingnói chung.

asyncio(kỹ thuật này không chỉ có sẵn trong Python, các ngôn ngữ và / hoặc khung công tác khác cũng có nó, ví dụ: Boost.ASIO ) là một phương pháp để xử lý hiệu quả nhiều hoạt động I / O từ nhiều nguồn đồng thời mà không cần thực thi mã song song . Vì vậy, nó chỉ là một giải pháp (thực sự là một giải pháp tốt!) Cho một tác vụ cụ thể, không phải để xử lý song song nói chung.


7
Lưu ý rằng mặc dù cả ba có thể không đạt được tính song song, chúng đều có khả năng thực hiện các tác vụ đồng thời (không chặn).
sargas

68

[Câu trả lời nhanh]

TL; DR

Đưa ra lựa chọn đúng:

Chúng ta đã xem qua các hình thức phổ biến nhất của đồng thời. Nhưng câu hỏi vẫn còn - khi nào nên chọn cái nào? Nó thực sự phụ thuộc vào các trường hợp sử dụng. Từ kinh nghiệm của tôi (và đọc), tôi có xu hướng làm theo mã giả này:

if io_bound:
    if io_very_slow:
        print("Use Asyncio")
    else:
        print("Use Threads")
else:
    print("Multi Processing")
  • CPU Bound => Đa xử lý
  • I / O Bound, Fast I / O, Limited Number of Connecting => Multi Threading
  • I / O Bound, I / O chậm, Nhiều kết nối => Asyncio

Tài liệu tham khảo


[ LƯU Ý ]:

  • Nếu bạn có một phương thức gọi dài (tức là một phương thức có thời gian ngủ hoặc I / O lười biếng), lựa chọn tốt nhất là phương pháp asyncio , Twisted hoặc Tornado (phương thức coroutine), hoạt động với một luồng duy nhất như là phương thức đồng thời.
  • asyncio hoạt động trên Python3.4 trở lên.
  • TornadoTwisted đã sẵn sàng kể từ Python2.7
  • uvloopasynciovòng lặp sự kiện cực nhanh ( uvloop làm cho asyncionhanh hơn 2-4 lần).

[CẬP NHẬT (2019)]:

  • Japranto ( GitHub ) là một máy chủ HTTP tổng hợp rất nhanh dựa trên uvloop .

Vì vậy, nếu tôi có một danh sách các url để yêu cầu, tốt hơn là sử dụng Asyncio ?
mingchau

1
@mingchau, Có, nhưng giữ trong tâm trí, bạn có thể sử dụng từ asynciokhi bạn sử dụng chức năng từ awaitable, requestthư viện không phải là một phương pháp awaitable, thay vì đó bạn có thể sử dụng như aiohttpthư viện hoặc async-yêu cầu và vv
Benyamin Jafari

vui lòng mở rộng trên slowIO và fastIO để đi đa luồng hoặc asyncio>?
qrtLs

1
Vui lòng cho bạn lời khuyên chính xác io_very_slow là gì
biến

1
Giới hạn I / O @variable nghĩa là chương trình của bạn dành phần lớn thời gian để nói chuyện với một thiết bị chậm, như kết nối mạng, ổ cứng, máy in hoặc vòng lặp sự kiện có thời gian ngủ. Vì vậy, trong chế độ chặn, bạn có thể chọn giữa phân luồng hoặc asyncio và nếu phần giới hạn của bạn rất chậm, đa nhiệm hợp tác (asyncio) là lựa chọn tốt hơn (tức là tránh để tài nguyên bị đói, khóa chết và điều kiện đua)
Benyamin Jafari

8

Đây là ý tưởng cơ bản:

IO -BOUND? ---------> SỬ DỤNGasyncio

NÓ LÀ CPU -HEAVY? -----> SỬ DỤNGmultiprocessing

HẠ? ----------------------> SỬ DỤNGthreading

Vì vậy, về cơ bản bám vào luồng trừ khi bạn gặp vấn đề về IO / CPU.


0

Trong đa xử lý, bạn tận dụng nhiều CPU để phân phối các phép tính của mình. Vì mỗi CPU chạy song song, bạn có thể chạy nhiều tác vụ đồng thời một cách hiệu quả. Bạn muốn sử dụng đa xử lý cho giới hạn CPU tác vụ . Một ví dụ sẽ là cố gắng tính tổng tất cả các phần tử của một danh sách lớn. Nếu máy của bạn có 8 lõi, bạn có thể "cắt" danh sách thành 8 danh sách nhỏ hơn và tính tổng của từng danh sách đó riêng biệt trên lõi riêng biệt và sau đó chỉ cần cộng các số đó lại. Bạn sẽ nhận được tốc độ tăng lên ~ 8x khi làm điều đó.

Trong luồngbạn không cần nhiều CPU. Hãy tưởng tượng một chương trình gửi nhiều yêu cầu HTTP đến web. Nếu bạn đã sử dụng một chương trình đơn luồng, nó sẽ dừng thực thi (khối) ở mỗi yêu cầu, đợi phản hồi và sau đó tiếp tục khi nhận được phản hồi. Vấn đề ở đây là CPU của bạn không thực sự hoạt động trong khi chờ một số máy chủ bên ngoài thực hiện công việc; nó có thể thực sự thực hiện một số công việc hữu ích trong thời gian chờ đợi! Cách khắc phục là sử dụng các chuỗi - bạn có thể tạo nhiều chuỗi, mỗi chuỗi chịu trách nhiệm yêu cầu một số nội dung từ web. Điều thú vị về các luồng là, ngay cả khi chúng chạy trên một CPU, thỉnh thoảng CPU sẽ "đóng băng" việc thực thi một luồng và chuyển sang thực thi luồng kia (nó được gọi là chuyển đổi ngữ cảnh và nó xảy ra liên tục ở mức không xác định khoảng thời gian). - sử dụng ren.

asyncio về cơ bản là phân luồng không phải CPU mà là bạn, với tư cách là một lập trình viên (hoặc thực sự là ứng dụng của bạn), quyết định vị trí và thời điểm diễn ra chuyển đổi ngữ cảnh . Trong Python, bạn sử dụng một awaittừ khóa để tạm dừng việc thực thi chương trình đăng quang của mình (được định nghĩa bằng asynctừ khóa).

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.