Python-queue.task_done()用于什么?

Python-queue.task_done()用于什么?,python,queue,task,Python,Queue,Task,我编写了一个脚本,它有多个线程(使用线程.Thread创建),使用队列.get_nowait()从队列中获取URL,然后处理HTML。我是多线程编程新手,在理解queue.task_done()函数的用途时遇到困难 当队列为空时,它会自动返回队列.empty异常。因此,我不理解每个线程调用task\u done()函数的必要性。我们知道当队列为空时,我们已经完成了队列的处理,那么为什么我们需要通知它工作线程已经完成了它们的工作(这与队列无关,在它们从队列中获取URL之后) 有人能给我提供一个代码

我编写了一个脚本,它有多个线程(使用
线程.Thread
创建),使用
队列.get_nowait()
队列中获取URL,然后处理HTML。我是多线程编程新手,在理解
queue.task_done()
函数的用途时遇到困难

队列
为空时,它会自动返回
队列.empty
异常。因此,我不理解每个线程调用
task\u done()
函数的必要性。我们知道当队列为空时,我们已经完成了队列的处理,那么为什么我们需要通知它工作线程已经完成了它们的工作(这与队列无关,在它们从队列中获取URL之后)


有人能给我提供一个代码示例(理想情况下使用
urllib
、文件I/O或fibonacci数字以外的其他东西并打印“Hello”),向我展示如何在实际应用中使用此函数吗

排队。完成的任务不符合工人的利益。它支持
队列。加入


如果我给你一盒作业,我在乎你什么时候把所有东西都拿出来吗

不。我关心工作何时完成。看着一个空盒子并不能告诉我这一点。你和其他5个人可能还在做你从盒子里拿出来的东西


Queue.task_done
让工作人员说出任务何时完成。等待使用
Queue.join完成所有工作的人将等待足够的
task\u done
调用完成,而不是队列为空时

有人能给我提供一个代码示例(理想情况下使用urllib、文件I/O或其他非斐波那契数和打印“Hello”)来说明如何在实际应用中使用此函数吗

@user2357112很好地解释了
task_done
的目的,但缺少所需的示例。这是一个函数,用于计算任意数量文件的校验和,并返回将每个文件名映射到相应校验和的dict。在函数内部,工作在多个线程之间分配

函数使用
Queue.join
等待工作人员完成分配的任务,因此可以安全地将字典返回给调用者。这是一种方便的方法,可以等待处理所有文件,而不仅仅是将它们排在队列中

import threading, queue, hashlib

def _work(q, checksums):
    while True:
        filename = q.get()
        if filename is None:
            q.put(None)
            break
        try:
            sha = hashlib.sha256()
            with open(filename, 'rb') as f:
                for chunk in iter(lambda: f.read(65536), b''):
                    sha.update(chunk)
            checksums[filename] = sha.digest()
        finally:
            q.task_done()

def calc_checksums(files):
    q = queue.Queue()
    checksums = {}
    for i in range(1):
        threading.Thread(target=_work, args=(q, checksums)).start()
    for f in files:
        q.put(f)
    q.join()
    q.put(None)  # tell workers to exit
    return checksums
关于GIL的注意事项:由于在计算校验和时,
hashlib
中的代码在内部释放GIL,因此与单线程变量相比,使用多线程会产生可测量的(1.75x-2x,取决于Python版本)加速。

.task_done()
用于标记
.join()
确认处理已完成

“卢克,读读消息来源!”——欧比一号,科多比

其来源相当短

  • 当您放入队列时,未完成任务的数量将增加1
  • 它下降了一倍,你称之为任务完成
  • join()等待没有未完成的任务
这使得join在且仅在调用task_done()时有用。使用经典的银行类比:

  • 人们进门排队;door是一个制作q.put()的制作人
  • 当出纳员空闲时,有人排队时,他们会进入出纳员窗口。teller执行一个q.get()
  • 当出纳员完成对该人的帮助后,他们就可以准备下一次了。出纳员做了一个问题任务
  • 下午5点,门被锁上,任务完成
  • 您将等待,直到两条线都是空的,并且每个出纳员都完成了对前面的人的帮助。等待q.加入(出纳员)
  • 然后你把出纳员送回家,他们现在都在空队中无所事事。对于出纳员中的出纳员:teller.cancel()

如果没有task_done(),您不可能知道每个出纳员都与人打交道。当出纳员有人在他或她的窗口时,您不能将其送回家。

是的,但我想问的是,为什么队列需要知道任务(即处理HTML、将提取的数据插入数据库等)何时完成?当它是空的,我就不干了。当抛出
queue.Empty
异常时,为什么我不能知道我已经完成了?为什么一个URL队列需要知道我成功地在数据库中输入了一些内容,或者处理了一些HTML?队列应该关心的是是否所有URL都已发送到某个线程。@J.Taylor:调用
queue.join
的人需要知道。@J.Taylor:取决于谁需要知道工作已完成,以及工作是否在工作完成时添加到队列中。工人们不需要调用
task\u done
来了解他们是否完成了任务
task_done
是一种与任何等待工作完成的线程进行通信的方式。对我来说,暗示task_is_done/join语义的队列概念是不寻常的。如果队列是空的或是满的,那么它应该只关注放置和获取以及枯萎。不是任务完成的事。“我在这里吗?”ifelsemonkey它在一个非常常见的使用场景中非常方便和有用,在工作人员之间分配任务。它只适用于你需要它的时候。如果您从未计划在队列上调用
join()
,您也不需要知道或关心
task\u done()
。为什么您需要额外的“If item is None:”测试,因为您永远无法访问它(除非您实际上在items\u队列中没有存储任何值,而您现在不这样做)?在我看来,如果队列为空,则会抛出空异常,因此执行将“跳转”到catch子句中。