[英]Two queues: the script doesn't exit
我編寫了一個使用2個隊列和3種類型的工作程序的腳本:生產者,使用者(CPU綁定任務),寫入者(我需要順序寫入結果)。
這是我的代碼的簡化版本:
from queue import Queue
from threading import Thread
def compute_single_score(data):
#do lots of calculations
return 0.0
def producer(out_q, data_to_compute):
while stuff:
data = data_to_compute.popitem()
out_q.put(data)
out_q.put(_sentinel)
def consumer(in_q, out_q):
while True:
data = in_q.get()
if data is _sentinel:
in_q.put(_sentinel)
break
out_q.put([data[0], compute_single_score(*data)])
in_q.task_done()
def writer(in_q):
while True:
data = in_q.get()
if data is _sentinel:
in_q.put(_sentinel)
break
in_q.task_done()
if __name__ == '__main__':
_sentinel = object()
jobs_queue = Queue()
scores_queue = Queue()
t1 = Thread(target=producer, args=(jobs_queue, data_to_compute,))
t2 = Thread(target=consumer, args=(jobs_queue,scores_queue,))
t3 = Thread(target=consumer, args=(jobs_queue,scores_queue,))
t4 = Thread(target=consumer, args=(jobs_queue,scores_queue,))
t5 = Thread(target=consumer, args=(jobs_queue,scores_queue,))
t6 = Thread(target=consumer, args=(jobs_queue,scores_queue,))
t7 = Thread(target=consumer, args=(jobs_queue,scores_queue,))
t8 = Thread(target=consumer, args=(jobs_queue,scores_queue,))
t9 = Thread(target=writer, args=(scores_queue,))
t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); t6.start(); t7.start(); t8.start(); t9.start()
jobs_queue.join()
scores_queue.join()
print('File written')
它立即打印出“文件已寫入”,而不是等待隊列為空。 因此,盡管執行了所有計算,但腳本不會退出。 兩個線程似乎保持活動狀態。
非常感謝您的支持。
它確實等待隊列為空。 但是由於將事情放入隊列是在線程中發生的,所以到達.join()
行的速度.put()
發生的速度快。 因此,當到達.join()
隊列為空。
現在,我不確定由於生產者有一段while stuff
循環while stuff
試圖達到的目標。 我假設您要繼續處理,直到這種情況成立。 特別是您必須等到t1
線程退出,即
t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); t6.start(); t7.start(); t8.start(); t9.start()
t1.join() # <-- this is important
jobs_queue.join()
scores_queue.join()
print('File written')
否則,您將無法同步。
旁注1 :由於GIL,創建CPU綁定線程沒有意義。 如果您的線程沒有執行任何IO(並且它們沒有執行),那么在單線程時它的性能會更好。 那么至少有多個consumer
線程是沒有意義的。
注釋2 :請勿使用逗號。 這不是pythonic。 而是這樣做:
threads = []
threads.append(Thread(target=producer, args=(jobs_queue, data_to_compute,)))
threads.append(Thread(target=writer, args=(scores_queue,)))
for i in range(10):
threads.append(Thread(target=consumer, args=(jobs_queue,scores_queue,)))
for t in threads:
t.start()
threads[0].join()
注釋3 :當隊列為空時,您應該處理情況。 data = in_q.get()
將永遠阻塞,這意味着您的腳本不會退出(除非將線程標記為daemon
)。 您應該這樣做:
try:
data = in_q.get(timeout=1)
except queue.Empty:
# handle empty queue here, perhaps quit if t1 is not alive
# otherwise just continue the loop
if not t1.is_alive(): # <-- you have to pass t1 to the thread
break
else:
continue
然后在主線程的末尾連接所有線程(請參閱側注2 ):
for t in threads:
t.start()
for t in threads:
t.join()
print('File written')
現在,您甚至不必加入隊列。
這是我最后使用的代碼(根據前面說明的要求):
from multiprocessing import JoinableQueue
from multiprocessing import Process
def compute_single_score(data):
#do lots of calculations
return 0.0
def producer(out_q, data_to_compute):
while stuff:
data = data_to_compute.popitem()
out_q.put(data)
def consumer(in_q, out_q):
while True:
try:
data = in_q.get(timeout=5)
except:
break
out_q.put([data[0], compute_single_score(*data)])
in_q.task_done()
def writer(in_q):
while True:
try:
data = in_q.get(timeout=5)
except:
break
#write
in_q.task_done()
if __name__ == '__main__':
jobs_queue = JoinableQueue()
scores_queue = JoinableQueue()
processes = []
processes.append(Process(target=producer, args=(jobs_queue, data_to_compute,)))
processes.append(Process(target=writer, args=(scores_queue,)))
for i in range(10):
processes.append(Process(target=consumer, args=(jobs_queue,scores_queue,)))
for p in processes:
p.start()
processes[1].join()
scores_queue.join()
print('File written')
我希望這會對其他人有所幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.