2012-03-14 41 views
7

Tôi đang sử dụng Threading.Event khá chuẩn: chủ đề chính được đến một điểm mà nó trong một vòng lặp chạy:giải pháp tốt hơn cho Python Threading.Event bán bận rộn chờ đợi

event.wait(60) 

Các khối khác trên một yêu cầu cho đến khi trả lời có sẵn và sau đó khởi tạo một:

event.set() 

tôi mong chờ các chủ đề chính để lựa chọn trong 40 giây, nhưng đây không phải là trường hợp. Từ nguồn Python 2.7 Lib/threading.py:

# Balancing act: We can't afford a pure busy loop, so we 
# have to sleep; but if we sleep the whole timeout time, 
# we'll be unresponsive. The scheme here sleeps very 
# little at first, longer as time goes on, but never longer 
# than 20 times per second (or the timeout time remaining). 
endtime = _time() + timeout 
delay = 0.0005 # 500 us -> initial delay of 1 ms 
while True: 
    gotit = waiter.acquire(0) 
    if gotit: 
     break 
    remaining = endtime - _time() 
    if remaining <= 0: 
     break 
    delay = min(delay * 2, remaining, .05) 
    _sleep(delay) 

Những gì chúng ta nhận được là một chọn syscall chạy mỗi 500us. Điều này gây ra tải đáng chú ý trên máy với một vòng lặp chọn khá chặt chẽ.

Ai đó có thể vui lòng giải thích lý do tại sao có một hành động cân bằng có liên quan và tại sao nó khác với một chuỗi đang chờ trên bộ mô tả tệp.

và thứ hai, Có cách nào tốt hơn để thực hiện chủ đề chính chủ yếu là ngủ mà không có vòng lặp chặt chẽ như vậy không?

Trả lời

3

Gần đây tôi đã bị ảnh hưởng bởi cùng một sự cố và tôi cũng đã theo dõi nó xuống khối mã chính xác này trong mô-đun threading.

Nó hút.

Giải pháp sẽ là quá tải mô-đun luồng hoặc di chuyển đến python3, nơi phần này của quá trình triển khai đã được khắc phục.

Trong trường hợp của tôi, việc chuyển sang python3 sẽ là một nỗ lực rất lớn, vì vậy tôi đã chọn trước đây. Những gì tôi đã làm là:

  1. Tôi tạo ra một tập tin .so nhanh (sử dụng cython) với một giao diện để pthread. Nó bao gồm các hàm python gọi hàm pthread_mutex_* tương ứng và liên kết với libpthread. Cụ thể, hàm có liên quan nhất đến nhiệm vụ mà chúng tôi quan tâm là pthread_mutex_timedlock.
  2. Tôi đã tạo mô-đun threading2 mới, (và thay thế tất cả các dòng import threading trong codebase của tôi bằng import threading2). Trong threading2, tôi đang xác định tất cả các lớp có liên quan từ threading (Lock, Condition, Event), và cũng có những người từ Queue mà tôi sử dụng rất nhiều (QueuePriorityQueue). Lớp Lock được triển khai lại hoàn toàn bằng cách sử dụng các chức năng pthread_mutex_*, nhưng phần còn lại dễ dàng hơn nhiều - tôi chỉ đơn giản là phân lớp gốc (ví dụ: threading.Event) và ghi đè __init__ để tạo loại Lock mới. Phần còn lại chỉ hoạt động.

Việc thực hiện mới Lock loại là rất giống với việc thực hiện ban đầu trong threading, nhưng tôi dựa trên các implemenation mới của acquire trên mã tôi tìm thấy trong threading mô-đun python3 's (trong đó, một cách tự nhiên, đơn giản hơn nhiều hơn khối "cân bằng hành động" nêu trên). Phần này khá dễ dàng.

(Btw, kết quả trong trường hợp của tôi là 30% tăng tốc của quy trình ồ ạt đa luồng của tôi. Thậm chí nhiều hơn tôi mong đợi.)

2

Tôi hoàn toàn đồng ý với bạn, điều này thật đáng tiếc.

Hiện tại, tôi đang gắn bó với một cuộc gọi chọn đơn giản, không có thời gian chờ và nghe trên một đường ống được tạo trước đây. Việc đánh thức được thực hiện bằng cách viết một ký tự trong đường ống.

Xem các chức năng này sleepwakeup từ gunicorn.

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