2008-08-27 26 views
73

Tôi đã cố gắng để quấn quanh đầu của tôi như thế nào chủ đề làm việc trong Python, và thật khó để tìm thông tin tốt về cách họ hoạt động. Tôi có thể thiếu liên kết hoặc một thứ gì đó, nhưng có vẻ như tài liệu chính thức không phải là rất kỹ lưỡng về chủ đề này, và tôi đã không thể tìm thấy một bài viết hay.Các luồng hoạt động như thế nào trong Python, và những cạm bẫy cụ thể của Python là gì?

Từ những gì tôi có thể biết, chỉ một luồng có thể chạy cùng một lúc và chuỗi hoạt động sẽ chuyển đổi mỗi 10 hướng dẫn hoặc như vậy?

Giải thích tốt ở đâu, hoặc bạn có thể cung cấp một giải thích không? Nó cũng sẽ rất tốt đẹp để được nhận thức của các vấn đề phổ biến mà bạn chạy vào trong khi sử dụng các chủ đề với Python.

Trả lời

46

Vâng, vì Interpreter Khóa toàn cầu (GIL) chỉ có thể chạy một luồng tại một thời điểm.Dưới đây là một số liên kết với một số hiểu biết về vấn đề này:

Từ liên kết cuối cùng một báo thú vị:

Hãy để tôi giải thích những gì tất cả những gì có nghĩa. Chủ đề chạy bên trong cùng một máy ảo và do đó chạy trên cùng một máy vật lý . Quy trình có thể chạy trên cùng một máy vật lý hoặc trong một máy vật lý khác. Nếu bạn kiến ​​trúc sư ứng dụng của bạn xung quanh chủ đề, bạn đã không thực hiện gì để truy cập nhiều máy. Vì vậy, bạn có thể chia tỷ lệ thành nhiều lõi trên một máy đơn lẻ (sẽ hoàn toàn là một số ít theo thời gian), nhưng thực sự đạt đến quy mô trên web, bạn sẽ cần giải quyết vấn đề nhiều máy .

Nếu bạn muốn sử dụng đa lõi, pyprocessing xác định API dựa trên quy trình để thực hiện song song thực. PEP cũng bao gồm một số điểm chuẩn thú vị.

+1

Thực sự là một bình luận trên báo giá smoothspan: chắc chắn Python luồng có hiệu quả giới hạn bạn đến một lõi, ngay cả khi máy có nhiều?Có thể có lợi ích từ đa lõi vì chuỗi tiếp theo có thể sẵn sàng để chuyển đi mà không cần chuyển ngữ cảnh, nhưng các chuỗi Python của bạn không bao giờ có thể sử dụng> 1 lõi cùng một lúc. –

+2

Chính xác, các chủ đề python thực tế bị giới hạn ở một lõi, mô-đun UNLESS C tương tác độc đáo với GIL và chạy chủ đề riêng của nó. – Arafangion

+0

Trên thực tế, nhiều lõi tạo ra các luồng _less_ hiệu quả vì có rất nhiều sự lộn xộn với việc kiểm tra xem mỗi luồng có thể truy cập GIL hay không. Ngay cả wit mới GIL, hiệu suất vẫn còn tồi tệ hơn ... http://www.dabeaz.com/python/NewGIL.pdf – Basic

18

Dưới đây là mẫu luồng cơ bản. Nó sẽ sinh ra 20 luồng; mỗi luồng sẽ xuất số chuỗi của nó. Chạy nó và quan sát thứ tự mà chúng in.

import threading 
class Foo (threading.Thread): 
    def __init__(self,x): 
     self.__x = x 
     threading.Thread.__init__(self) 
    def run (self): 
      print str(self.__x) 

for x in xrange(20): 
    Foo(x).start() 

Như bạn đã gợi ý về các chuỗi Python được triển khai thông qua việc cắt thời gian. Đây là cách họ nhận được hiệu ứng "song song".

Trong ví dụ của tôi, lớp Foo của tôi mở rộng chuỗi, sau đó, tôi triển khai phương thức run, là nơi mã bạn muốn chạy trong chuỗi. Để bắt đầu chuỗi bạn gọi start() trên đối tượng chuỗi, sẽ tự động gọi phương thức run ...

Tất nhiên, đây chỉ là những điều cơ bản. Cuối cùng bạn sẽ muốn tìm hiểu về semaphores, mutexes, và khóa cho đồng bộ hóa thread và thông điệp đi qua.

34

Python là một ngôn ngữ khá dễ dàng để tạo luồng, nhưng hãy cẩn thận. Điều quan trọng nhất bạn cần biết là Khóa thông dịch toàn cầu. Điều này chỉ cho phép một luồng truy cập thông dịch viên. Điều này có nghĩa là hai điều: 1) bạn hiếm khi tìm thấy chính mình bằng cách sử dụng một tuyên bố khóa trong python và 2) nếu bạn muốn tận dụng lợi thế của các hệ thống đa xử lý, bạn phải sử dụng các quy trình riêng biệt. EDIT: Tôi cũng nên chỉ ra rằng bạn có thể đặt một số mã trong C/C++ nếu bạn muốn nhận được xung quanh GIL là tốt.

Vì vậy, bạn cần xem xét lại lý do bạn muốn sử dụng chuỗi. Nếu bạn muốn song song ứng dụng của mình để tận dụng kiến ​​trúc lõi kép, bạn cần cân nhắc việc chia nhỏ ứng dụng của mình thành nhiều quy trình.

Nếu bạn muốn cải thiện khả năng phản hồi, bạn nên xem xét sử dụng chuỗi. Có những lựa chọn thay thế khác, cụ thể là microthreading. Ngoài ra còn có một số khuôn khổ mà bạn nên xem xét:

+0

@JS - Đã sửa lỗi. Danh sách đó đã lỗi thời. –

+0

Nó chỉ cảm thấy sai với tôi rằng bạn cần nhiều quy trình - với tất cả các chi phí đòi hỏi - để tận dụng lợi thế của một hệ thống đa lõi. Chúng tôi có một số máy chủ với 32 lõi logic - vì vậy tôi cần 32 quy trình để sử dụng chúng hiệu quả? Madness – Basic

+0

@Basic - Các chi phí trong việc bắt đầu một quá trình vs bắt đầu một chủ đề những ngày này là tối thiểu. Tôi cho rằng bạn có thể bắt đầu thấy vấn đề nếu chúng ta đang nói về hàng ngàn truy vấn mỗi giây, nhưng sau đó tôi sẽ đặt câu hỏi về sự lựa chọn của Python cho một dịch vụ bận rộn như vậy ngay từ đầu. –

9

Sử dụng các chuỗi trong python nếu các công nhân riêng lẻ đang thực hiện các hoạt động liên kết I/O. Nếu bạn đang cố gắng mở rộng trên nhiều lõi trên máy hoặc tìm một khung IPC tốt cho python hoặc chọn một ngôn ngữ khác.

1

Hãy thử nhớ rằng GIL được đặt thành cuộc thăm dò ý kiến ​​xung quanh mọi việc thường xuyên để hiển thị sự xuất hiện của nhiều tác vụ. Thiết lập này có thể được tinh chỉnh, nhưng tôi đưa ra gợi ý rằng cần có công việc mà các luồng đang làm hoặc rất nhiều công tắc ngữ cảnh sẽ gây ra vấn đề.

Tôi sẽ đi xa đến mức đề xuất nhiều phụ huynh về bộ xử lý và cố gắng giữ công việc giống nhau trên cùng một (các) lõi.

2

Một giải pháp dễ dàng cho GIL là mô-đun multiprocessing. Nó có thể được sử dụng như là một giọt thay thế cho các mô-đun luồng nhưng sử dụng nhiều quá trình thông dịch thay vì các chủ đề. Bởi vì điều này có nhiều hơn một chút chi phí hơn luồng đồng bằng cho những điều đơn giản nhưng nó mang lại cho bạn lợi thế của song song thực nếu bạn cần nó. Nó cũng dễ dàng chia tỷ lệ cho nhiều máy vật lý.

Nếu bạn cần song song quy mô lớn hơn tôi sẽ xem xét thêm, nhưng nếu bạn chỉ muốn chia tỷ lệ cho tất cả các lõi của một máy tính hoặc một vài máy tính khác nhau mà không cần phải thực hiện một khuôn khổ toàn diện hơn cái này dành cho bạn.

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