Tài liệu Python 3.7
Tôi cũng muốn làm nổi bật trích dẫn sau đây từ tài liệu Pythonthreading
:
Chi tiết triển khai CPython: Trong CPython, do Khóa phiên dịch toàn cầu, chỉ một luồng có thể thực thi mã Python cùng một lúc (ngay cả khi các thư viện hướng hiệu suất nhất định có thể khắc phục giới hạn này). Nếu bạn muốn ứng dụng của mình sử dụng tốt hơn các tài nguyên tính toán của các máy đa lõi, bạn nên sử dụng multiprocessing
hoặc concurrent.futures.ProcessPoolExecutor
. Tuy nhiên, luồng vẫn là một mô hình thích hợp nếu bạn muốn chạy đồng thời nhiều tác vụ ràng buộc I / O.
Liên kết này với mục Thuật ngữglobal interpreter lock
giải thích rằng GIL ngụ ý rằng tính song song của luồng trong Python là không phù hợp với các tác vụ bị ràng buộc của CPU :
Cơ chế được trình thông dịch CPython sử dụng để đảm bảo rằng chỉ có một luồng thực thi mã byte Python tại một thời điểm. Điều này đơn giản hóa việc triển khai CPython bằng cách tạo mô hình đối tượng (bao gồm các loại tích hợp quan trọng như dict) hoàn toàn an toàn trước truy cập đồng thời. Việc khóa toàn bộ trình thông dịch giúp trình thông dịch trở nên đa luồng dễ dàng hơn, với chi phí của phần lớn tính song song được cung cấp bởi các máy đa bộ xử lý.
Tuy nhiên, một số mô-đun mở rộng, theo tiêu chuẩn hoặc bên thứ ba, được thiết kế để giải phóng GIL khi thực hiện các tác vụ chuyên sâu tính toán như nén hoặc băm. Ngoài ra, GIL luôn được phát hành khi thực hiện I / O.
Những nỗ lực trong quá khứ để tạo ra một trình thông dịch, luồng dữ liệu miễn phí (một khóa khóa dữ liệu được chia sẻ ở mức độ chi tiết tốt hơn nhiều) đã không thành công vì hiệu năng bị ảnh hưởng trong trường hợp bộ xử lý đơn thông thường. Người ta tin rằng việc khắc phục vấn đề hiệu suất này sẽ khiến việc thực hiện phức tạp hơn nhiều và do đó tốn kém hơn để duy trì.
Trích dẫn này cũng ngụ ý rằng các lệnh và do đó việc gán biến cũng là luồng an toàn như một chi tiết triển khai CPython:
Tiếp theo, các tài liệu cho multiprocessing
gói giải thích cách nó vượt qua GIL bằng cách sinh ra quá trình trong khi phơi bày một giao diện tương tự như threading
:
đa xử lý là gói hỗ trợ các quá trình sinh sản bằng cách sử dụng API tương tự như mô-đun luồng. Gói đa xử lý cung cấp cả đồng thời cục bộ và từ xa, bước hiệu quả bên cạnh Khóa phiên dịch toàn cầu bằng cách sử dụng các quy trình con thay vì các luồng. Do đó, mô-đun đa xử lý cho phép lập trình viên tận dụng triệt để nhiều bộ xử lý trên một máy nhất định. Nó chạy trên cả Unix và Windows.
Và các tài liệu đểconcurrent.futures.ProcessPoolExecutor
giải thích rằng nó sử dụng multiprocessing
như một phụ trợ:
Lớp ProcessPoolExecutor là một lớp con Executor sử dụng một nhóm các quy trình để thực hiện các cuộc gọi không đồng bộ. ProcessPoolExecutor sử dụng mô-đun đa xử lý, cho phép nó bước bên cạnh Khóa phiên dịch toàn cầu nhưng cũng có nghĩa là chỉ các đối tượng có thể chọn được mới có thể được thực thi và trả về.
cần được trái ngược với phân lớp cơ sở khác ThreadPoolExecutor
mà sử dụng đề thay vì quy trình
ThreadPoolExecutor là một lớp con Executor sử dụng một nhóm các luồng để thực hiện các cuộc gọi không đồng bộ.
từ đó chúng tôi kết luận rằng ThreadPoolExecutor
chỉ phù hợp với các tác vụ bị ràng buộc I / O, trong khi ProcessPoolExecutor
cũng có thể xử lý các tác vụ bị ràng buộc của CPU.
Câu hỏi sau đây hỏi tại sao GIL tồn tại ở vị trí đầu tiên: Tại sao Khóa phiên dịch toàn cầu?
Quá trình so với thí nghiệm luồng
Tại Multiprocessing vs Threading Python Tôi đã thực hiện một phân tích thử nghiệm về quy trình so với các luồng trong Python.
Xem trước nhanh kết quả: