【问题标题】:When is Queue.join() necessary?什么时候需要 Queue.join()?
【发布时间】:2017-07-13 01:40:59
【问题描述】:

Python 3 文档给出了一个使用队列 (https://docs.python.org/3/library/queue.html) 的工作线程示例:

def worker():
    while True:
        item = q.get()
        if item is None:
            break
        do_work(item)
        q.task_done()

q = queue.Queue()
threads = []
for i in range(num_worker_threads):
    t = threading.Thread(target=worker)
    t.start()
    threads.append(t)

for item in source():
    q.put(item)

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

# stop workers
for i in range(num_worker_threads):
    q.put(None)
for t in threads:
    t.join()

在这个例子中,为什么需要q.join()?后续的q.put(None)t.join() 操作是否完成了阻塞主线程直到工作线程完成的相同事情?

【问题讨论】:

    标签: python multithreading python-3.x queue


    【解决方案1】:

    这是我对示例的理解。

    每个工人无限循环,总是从队列中寻找新的东西。如果它获得的项目是None,它会中断并将控制权返回给main。

    所以,首先我们让程序等待队列为空。每次调用q.task_done() 都会将新项目标记为完成。代码挂在下面,所以我们确保每个项目都标记为完成。

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

    然后,在下面,我们将与工作人员数量相同的 None 项目添加到队列中(因此我们确保每个工作人员都获得一个。)

    for i in range(num_worker_threads):
        q.put(None)
    

    接下来,我们加入所有线程。由于我们通过队列给了每个工人一个None 项目,他们都会中断。直到他们都打破并返回控制权,我们想挂在这里。

    for t in threads:
        t.join()
    

    这样做,我们确保队列中的每一项都得到处理,当队列为空时,每个工作人员都会中断,并且在我们继续编写代码之前关闭每个工作人员,从而有助于避免孤儿进程。

    【讨论】:

    • 我也是这么解释这个例子的。所以,我的问题是,即使我们删除q.join() 语句,队列中的每个项目是否都已处理(并且所有线程都已清理)?通过加入所有工作线程(最后一步),我们仍在等待队列中的所有项目得到处理。
    • 是的,我们仍在等待,但我认为这是一种编码安全措施。如果在处理队列中的所有项目并且一个工人得到一个之前奇迹般地添加了None,会怎样?我认为这只是一个繁琐的编程示例,以确保您了解正在发生的事情,而不必完全了解队列进入 FIFO(先进先出)。此外,此示例可适用于 LIFO(后进先出)实现。但是,对于当前的示例,我相信您可以取出 q.join() 并且会很好。
    猜你喜欢
    • 1970-01-01
    • 2012-09-16
    • 1970-01-01
    • 2018-12-10
    • 2010-12-29
    • 2012-08-21
    • 2011-08-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多