Hướng dẫn why python is not good for multithreading? - tại sao python không tốt cho đa luồng?

Trong bài viết này, trước tiên tôi sẽ hướng dẫn bạn sự khác biệt giữa lập trình đồng thời và thực hiện song song, thảo luận về các cơ chế lập trình đồng thời của Python và những cạm bẫy của đa luồng trong Python.

Hiểu lập trình đồng thời so với thực hiện song song

Lập trình đồng thời không tương đương với việc thực hiện song song, mặc dù thực tế là hai thuật ngữ này thường được sử dụng thay thế cho nhau.

Minh họa về sự đồng thời mà không có sự song song

Đồng thời là một thuộc tính mà nhiều hơn một thao tác có thể được chạy đồng thời nhưng nó không có nghĩa là nó sẽ có. (Hãy tưởng tượng nếu bộ xử lý của bạn là một luồng đơn.)

Minh họa song song

Song song là một thuộc tính mà các hoạt động thực sự đang được chạy đồng thời. Nó thường được xác định bởi các ràng buộc phần cứng.

Hãy nghĩ về chương trình của bạn như một chuỗi thức ăn nhanh, đồng thời được kết hợp khi hai bộ đếm riêng biệt cho đơn hàng và thu thập được xây dựng. Tuy nhiên, nó không đảm bảo sự song song vì nó phụ thuộc vào số lượng nhân viên có sẵn. Nếu chỉ có một nhân viên xử lý cả yêu cầu đặt hàng và thu thập, các hoạt động có thể chạy song song. Sự song song chỉ có mặt khi có hai nhân viên phục vụ đồng thời và thu thập.

Python xây dựng

Bây giờ, chúng ta có gì ở Python? Liệu Python đã xây dựng các kết quả tạo điều kiện cho chúng ta xây dựng các chương trình đồng thời và cho phép chúng chạy song song?

Trong các cuộc thảo luận sau đây, chúng tôi giả sử các chương trình của chúng tôi đều được viết và chạy trong bộ xử lý đa luồng hoặc đa lõi.

Câu trả lời là Jein (có và không trong tiếng Đức). Tại sao có? Python có các thư viện tích hợp cho các cấu trúc lập trình đồng thời phổ biến nhất-đa xử lý và đa luồng. Bạn có thể nghĩ, vì Python hỗ trợ cả hai, tại sao Jein? Lý do là, đa luồng trong Python không thực sự là đa luồng, do Gil trong Python.Jein (Yes and No in German). Why yes? Python does have built-in libraries for the most common concurrent programming constructs — multiprocessing and multithreading. You may think, since Python supports both, why Jein? The reason is, multithreading in Python is not really multithreading, due to the GIL in Python.

Đa luồng-song song dựa trên chủ đề

threading là gói cung cấp API để tạo và quản lý các luồng. Các chủ đề trong Python luôn không xác định và lịch trình của chúng được thực hiện bởi hệ điều hành. Tuy nhiên, đa luồng có thể không làm những gì bạn mong đợi.

Tại sao đa luồng trong Python có thể không phải là những gì bạn & nbsp; muốn?

Khác với những cạm bẫy phổ biến như bế tắc, chết đói trong đa luồng nói chung. Python nổi tiếng với hiệu suất kém trong đa luồng.

Chúng ta hãy nhìn vào đoạn trích sau:

nhập luồng

Def Countdown (): x = 1000000000 trong khi x> 0: x -= 1

# Triển khai 1: Multi-threadingDef Triển khai_1 (): Thread_1 = Threading.Thread (Target = Countdown) Thread_2 = Threading.Thread (Target = Countdown) Thread_1.Start () Thread_2.start () )

# Triển khai 2: Chạy trong Triển khai Serialdef_2 (): Đếm ngược () Đếm ngược ()

Việc thực hiện nào sẽ nhanh hơn? Hãy để chúng tôi thực hiện một thời gian.

Kết quả thời gian của cả hai triển khai

Đáng ngạc nhiên, chạy 2 countdown() vượt trội so với đa luồng? Làm sao điều này xảy ra được? Nhờ khóa thông dịch viên toàn cầu khét tiếng (GIL).

Thuốc phiên dịch toàn cầu là gì & nbsp; (GIL) là gì?

Phụ thuộc vào sự phân phối của Python của bạn, mà hầu hết các trường hợp, là một triển khai của CPython. CPython là triển khai ban đầu của Python, bạn có thể đọc thêm về nó trong chuỗi StackOverflow này.

Trong Cpython, đa luồng được hỗ trợ bằng cách giới thiệu một mutex được gọi là khóa phiên dịch toàn cầu (còn gọi là Gil). Đó là để ngăn chặn nhiều luồng truy cập cùng một đối tượng Python cùng một lúc. Điều này có ý nghĩa, bạn sẽ không muốn người khác đột biến đối tượng của bạn trong khi bạn đang xử lý nó.

Minh họa thực hiện_1

Vì vậy, từ đoạn mã của chúng tôi ở trên, implementation_1 tạo ra 2 luồng và được cho là chạy song song trên một hệ thống đa luồng. Tuy nhiên, chỉ có một luồng có thể giữ GIL tại một thời điểm, một luồng phải đợi một luồng khác để giải phóng GIL trước khi chạy. Trong khi đó, lập lịch và chuyển đổi được thực hiện bởi hệ điều hành giới thiệu chi phí làm cho implementation_1 thậm chí chậm hơn.

Làm thế nào để bỏ qua & nbsp; gil?

Làm thế nào chúng ta có thể bỏ qua Gil, trong khi duy trì việc sử dụng đa luồng? Không có câu trả lời tốt cho câu hỏi này, vì điều này thay đổi theo mục đích của mã của bạn.

Sử dụng một triển khai khác của Python như Jython, Pypy hoặc IronPython là một lựa chọn. Cá nhân tôi không ủng hộ việc sử dụng một triển khai Python khác vì hầu hết các thư viện được viết không được kiểm tra chống lại các triển khai khác nhau của Python.

Một cách giải quyết tiềm năng khác là sử dụng C-Extension, hoặc được gọi là Cython. Lưu ý rằng Cython và Cpython không giống nhau. Bạn có thể đọc thêm về Cython ở đây.

Sử dụng đa xử lý thay thế. Kể từ khi đa xử lý, một thông dịch viên được tạo cho mỗi quá trình trẻ em. Tình huống mà các chủ đề đấu tranh cho Gil Simple không tồn tại vì luôn luôn có một chủ đề chính trong mọi quy trình.

Bất chấp tất cả những cạm bẫy, chúng ta vẫn nên sử dụng đa luồng?

Nếu nhiệm vụ của bạn là I/O bị ràng buộc, có nghĩa là luồng dành phần lớn thời gian để xử lý I/O như thực hiện các yêu cầu mạng. Vẫn là hoàn toàn tốt khi sử dụng đa luồng làm chủ đề, hầu hết thời gian, bị chặn và đưa vào hàng đợi bị chặn bởi HĐH. Chủ đề cũng luôn luôn đói tài nguyên hơn quá trình.

Đa xử lý-song song dựa trên quy trình

Hãy để chúng tôi thực hiện đoạn mã trước đây của chúng tôi bằng cách sử dụng đa xử lý.

Nhập đa xử lý

# Countdown () được định nghĩa trong đoạn trích trước.

DEF THỰC HIỆN_3 (): Process_1 = MultipRocessing.Process (Target = Countdown) Process_2 = Multiprocessing.Process (Target = Countdown) Process_1.start () Process_2.start ()

Kết quả là bản thân là tự giải thích.

Kết quả thời gian của đa bộ xử lý so với đa luồng

Sự kết luận

Hạn chế của Gil là một cái gì đó đã bắt tôi ngay từ đầu thời gian là một nhà phát triển Python. Tôi đã nhận thức được quyết định của tôi về việc sử dụng chủ đề là hoàn toàn vô giá trị cho đến khi tôi thực hiện thời gian. Tôi hy vọng bài viết này sẽ giúp.

Vui lòng nhấp vào nút 👏 nếu bạn thấy điều này hữu ích.

ĐANG TẢI. . . Nhận xét và nhiều hơn nữa!
. . . comments & more!

Là đa

Để tóm tắt lại, luồng trong Python cho phép nhiều luồng được tạo trong một quy trình duy nhất, nhưng do Gil, không ai trong số chúng sẽ chạy cùng một lúc. Chủ đề vẫn là một lựa chọn rất tốt khi chạy nhiều tác vụ ràng buộc I/O đồng thời.Threading is still a very good option when it comes to running multiple I/O bound tasks concurrently.

Tại sao Python không phải chủ đề

Python không an toàn cho luồng và ban đầu được thiết kế với một thứ gọi là Gil, hoặc khóa thông dịch toàn cầu, đảm bảo các quy trình được thực thi theo chiều cao trên CPU của máy tính.Nhìn bề ngoài, điều này có nghĩa là các chương trình Python không thể hỗ trợ đa xử lý.originally designed with something called the GIL, or Global Interpreter Lock, that ensures processes are executed serially on a computer's CPU. On the surface, this means Python programs cannot support multiprocessing.

Tại sao Python chậm hơn MultiThreading?

Điều này là do Python Gil là nút cổ chai ngăn chặn các chủ đề chạy hoàn toàn đồng thời.Việc sử dụng CPU tốt nhất có thể có thể đạt được bằng cách sử dụng các mô -đun ProcessPoolExecutor hoặc Process, điều này phá vỡ GIL và làm cho mã chạy đồng thời hơn.due to the Python GIL being the bottleneck preventing threads from running completely concurrently. The best possible CPU utilisation can be achieved by making use of the ProcessPoolExecutor or Process modules which circumvents the GIL and make code run more concurrently.

Python có phải là một ngôn ngữ đa luồng không?

Cả Python và Ruby đều có hỗ trợ đầy đủ cho đa luồng.Có một số triển khai (ví dụ: Cpython, MRI, YARV) thực sự không thể chạy các luồng song song, nhưng đó là một hạn chế của các triển khai cụ thể đó, chứ không phải ngôn ngữ.. There are some implementations (e.g. CPython, MRI, YARV) which cannot actually run threads in parallel, but that's a limitation of those specific implementations, not the language.