簡體   English   中英

兩個隊列:腳本不退出

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM