2009-05-04 32 views
10

Nếu tôi có một chương trình sử dụng luồng và Hàng đợi, làm cách nào để có ngoại lệ để ngừng thực thi? Đây là một chương trình ví dụ, mà không thể dừng lại với ctrl-c (về cơ bản đã tách khỏi các tài liệu python).Làm cách nào để xử lý các ngoại lệ khi sử dụng luồng và Hàng đợi?

from threading import Thread 
from Queue import Queue 
from time import sleep 

def do_work(item): 
    sleep(0.5) 
    print "working" , item 

def worker(): 
     while True: 
      item = q.get() 
      do_work(item) 
      q.task_done() 

q = Queue() 

num_worker_threads = 10 

for i in range(num_worker_threads): 
    t = Thread(target=worker) 
    # t.setDaemon(True) 
    t.start() 

for item in range(1, 10000): 
    q.put(item) 

q.join()  # block until all tasks are done 

Trả lời

6

Cách đơn giản nhất là để bắt đầu tất cả các chủ đề công nhân như đề daemon, sau đó chỉ cần có vòng lặp chính của bạn được

while True: 
    sleep(1) 

nhấn Ctrl + C sẽ ném một ngoại lệ trong chủ đề chính của bạn, và tất cả các chuỗi daemon sẽ thoát khi trình thông dịch thoát. Điều này giả định bạn không muốn thực hiện dọn dẹp trong tất cả các luồng đó trước khi chúng thoát ra.

Một cách phức tạp hơn là phải có một toàn cầu stoppedEvent:

stopped = Event() 
def worker(): 
    while not stopped.is_set(): 
     try: 
      item = q.get_nowait() 
      do_work(item) 
     except Empty:  # import the Empty exception from the Queue module 
      stopped.wait(1) 

Sau đó, vòng lặp chính của bạn có thể thiết lập stopped tổ chức sự kiện để False khi nó được một KeyboardInterrupt

try: 
    while not stopped.is_set(): 
     stopped.wait(1) 
except KeyboardInterrupt: 
    stopped.set() 

này cho phép nhân viên của bạn chủ đề hoàn thành những gì họ đang làm bạn muốn thay vì chỉ có mỗi thread công nhân là một daemon và thoát ra ở giữa thực hiện. Bạn cũng có thể làm bất cứ điều gì bạn muốn.

Lưu ý rằng ví dụ này không sử dụng q.join() - điều này làm cho mọi thứ phức tạp hơn, mặc dù bạn vẫn có thể sử dụng nó. Nếu bạn làm vậy thì tốt nhất bạn nên sử dụng bộ xử lý tín hiệu thay vì ngoại lệ để phát hiện KeyboardInterrupt s. Ví dụ:

from signal import signal, SIGINT 
def stop(signum, frame): 
    stopped.set() 
signal(SIGINT, stop) 

Điều này cho phép bạn xác định điều gì xảy ra khi bạn nhấn Ctrl + C mà không ảnh hưởng đến bất kỳ vòng lặp chính nào của bạn ở giữa. Vì vậy, bạn có thể tiếp tục thực hiện q.join() mà không phải lo lắng về việc bị gián đoạn bởi Ctrl + C. Tất nhiên, với các ví dụ trên của tôi, bạn không cần phải tham gia, nhưng bạn có thể có một số lý do khác để làm như vậy.

+1

Vì vậy, về cơ bản, việc sử dụng q.join() khiến việc xử lý các ngoại lệ trong chuỗi có khó khăn không? –

+1

Không nên đọc "tín hiệu (SIGINT, dừng)"? – Ber

+0

Nó làm cho mọi thứ phức tạp hơn, nhưng tôi đã thêm một ví dụ với các tín hiệu để chỉ cho bạn cách bạn sử dụng q.join() nếu bạn có lý do chính đáng để sử dụng điều đó. –

1

A (có thể) lưu ý Offtopic:

(...) 
for item in range(1, 10000): 
    q.put(item) 
(...) 

Bạn có thể sử dụng xrange thay vì phạm vi ở đây (trừ khi bạn sử dụng python3000). Bạn sẽ tiết kiệm một số CPU và bộ nhớ bằng cách làm như vậy. Thông tin thêm về xrange có thể được tìm thấy here.

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