理解Queue队列中join()与task_done()的关系
在网上大多关于join()与task_done()的结束原话是这样的:
Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号Queue.join() 实际上意味着等到队列为空,再执行别的操作
理解
#!/usr/bin/env python# -*- coding:utf-8 -*-'''threading test'''import threadingimport queuefrom time import sleep#之所以为什么要用线程,因为线程可以start后继续执行后面的主线程,可以put数据,如果不是线程直接在get阻塞。class Mythread(threading.Thread):def __init__(self,que):threading.Thread.__init__(self)self.queue = quedef run(self):while True:sleep(1)if self.queue.empty(): #判断放到get前面,这样可以,否则队列最后一个取完后就空了,直接break,走不到printbreakitem = self.queue.get()print(item,'!')#self.queue.task_done()returnque = queue.Queue()tasks = [Mythread(que) for x in range(1)]for x in range(10):que.put(x) #快速生产for x in tasks:t = Mythread(que) #把同一个队列传入2个线程t.start()que.join()print('---success---')

def task_done(self):'''Indicate that a formerly enqueued task is complete.Used by Queue consumer threads. For each get() used to fetch a task,a subsequent call to task_done() tells the queue that the processingon the task is complete.If a join() is currently blocking, it will resume when all itemshave been processed (meaning that a task_done() call was receivedfor every item that had been put() into the queue).Raises a ValueError if called more times than there were itemsplaced in the queue.'''with self.all_tasks_done:unfinished = self.unfinished_tasks - 1if unfinished <= 0:if unfinished < 0:raise ValueError('task_done() called too many times')self.all_tasks_done.notify_all()self.unfinished_tasks = unfinished
快速生产-快速消费
上面的演示代码是快速生产-慢速消费的场景,我们可以直接用task_done()与join()配合,来让empty()判断出队列是否已经结束。 当然,queue我们可以正确判断是否已经清空,但是线程里的get队列是不知道,如果没有东西告诉它,队列空了,因此get还会继续阻塞,那么我们就需要在get程序中加一个判断,如果empty()成立,break退出循环,否则get()还是会一直阻塞。
慢速生产-快速消费
但是如果生产者速度与消费者速度相当,或者生产速度小于消费速度,则靠task_done()来实现队列减一则不靠谱,队列会时常处于供不应求的状态,常为empty,所以用empty来判断则不靠谱。 那么这种情况会导致 join可以判断出队列结束了,但是线程里不能依靠empty()来判断线程是否可以结束。 我们可以在消费队列的每个线程最后塞入一个特定的“标记”,在消费的时候判断,如果get到了这么一个“标记”,则可以判定队列结束了,因为生产队列都结束了,也不会再新增了。 代码如下:
#!/usr/bin/env python# -*- coding:utf-8 -*-'''threading test'''import threadingimport queuefrom time import sleep#之所以为什么要用线程,因为线程可以start后继续执行后面的主线程,可以put数据,如果不是线程直接在get阻塞。class Mythread(threading.Thread):def __init__(self,que):threading.Thread.__init__(self)self.queue = quedef run(self):while True:item = self.queue.get()self.queue.task_done() #这里要放到判断前,否则取最后最后一个的时候已经为空,直接break,task_done执行不了,join()判断队列一直没结束if item == None:breakprint(item,'!')returnque = queue.Queue()tasks = [Mythread(que) for x in range(1)]#快速生产for x in tasks:t = Mythread(que) #把同一个队列传入2个线程t.start()for x in range(10):sleep(1)que.put(x)for x in tasks:que.put(None)que.join()print('---success---')
注意点:
put队列完成的时候千万不能用task_done(),否则会报错:
task_done() called too many times
因为该方法仅仅表示get成功后,执行的一个标记。
理解Queue队列中join()与task_done()的关系的更多相关文章
- 在队列中join()与task_done()的关联性
1.基础解释: Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号 Queue.join() 实际上意味着等到队列为空,再执 ...
- python threading queue模块中join setDaemon及task_done的使用方法及示例
threading: t.setDaemon(True) 将线程设置成守护线程,主进行结束后,此线程也会被强制结束.如果线程没有设置此值,则主线程执行完毕后还会等待此线程执行. t. ...
- python中的Queue(队列)详解
一.Queue简介 python中的队列分类可分为两种: 1.线程Queue,也就是普通的Queue 2.进程Queue,在多线程与多进程会介绍. Queue的种类: FIFO: Queue.Que ...
- Java 集合深入理解(9):Queue 队列
点击查看 Java 集合框架深入理解 系列, - ( ゜- ゜)つロ 乾杯~ 今天心情不太好,来学一下 List 吧! 什么是队列 队列是数据结构中比较重要的一种类型,它支持 FIFO,尾部添加.头部 ...
- python多线程中join()的理解
在 Python 的多线程编程中,经常碰到 thread.join()这样的代码.那么今天咱们用实际代码来解释一下 join 函数的作用. 第一,当一个进程启动之后,会默认产生一个主线程,因为线程是程 ...
- 【服务总线 Azure Service Bus】ServiceBus 队列中死信(DLQ - Dead Letter Queue)问题
Azure Service Bus 死信队列产生的原因 服务总线中有几个活动会导致从消息引擎本身将消息推送到 DLQ. 如 超过 MaxDeliveryCount 超过 TimeToLive 处理订阅 ...
- Python守护进程、进程互斥锁、进程间通信ICP(Queue队列)、生产者消费者模型
知识点一:守护进程 守护进程:p1.daemon=True 守护进程其实就是一个“子进程“,守护=>伴随 守护进程会伴随主进程的代码运行完毕后而死掉 进程:当父进程需要将一个任务并发出去执行,需 ...
- 进击的Python【第九章】:paramiko模块、线程与进程、各种线程锁、queue队列、生产者消费者模型
一.paramiko模块 他是什么东西? paramiko模块是用python语言写的一个模块,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接. 先来个实例: import param ...
- Python 源码分析:queue 队列模块
起步 queue 模块提供适用于多线程编程的先进先出(FIFO)数据结构.因为它是线程安全的,所以多个线程很轻松地使用同一个实例. 源码分析 先从初始化的函数来看: 从这初始化函数能得到哪些信息呢?首 ...
随机推荐
- u-boot分析(八)----串口初始化
u-boot分析(八) 上篇博文我们按照210的启动流程,分析到了内存初始化,今天我们继续按照u-boot的启动流程对串口的初始化进行分析. 今天我们会用到的文档: 1. 2440芯片手 ...
- python 生成随机图片验证码
1.安装pillow模块 pip install pillow (1)创建图片 from PIL import Image #定义使用Image类实例化一个长为400px,宽为400px,基于RGB的 ...
- 使用BaiDu Java Script Web Api 在Web开发中嵌入地图使用步骤
前言 很多做企业网站的朋友,都喜欢有一个关于我们.联系我们的栏目,那么这个栏目放什么内容才能饱满那,只有放个地图才显得有点高大上. 一.产生并复制访问Api的密钥(AK) 1.首先我们需要注册一个百度 ...
- 给网站添加图标: Font Awesome
先贴上各种图标的网址:https://fontawesome.com/?from=io 1.打开网址,我们可以看到: 像我这种英语不好的,直接用谷歌浏览器进行翻译中文好了,自己还是有点B数的····· ...
- php session小节
1.为什么要用session? 在人们访问网站的时候,有很多个网页,由于http自身的特点,用户每执行一个脚本都需要和web服务器重新建立连接.由于他们之间是无状态的,这次的连接无法得到上次连接的状态 ...
- PHP获取系统时间不对的解决办法(转载)
原地址:https://blog.csdn.net/u012124764/article/details/51450958 使用PHP获取系统时间,发现时间不对,是因为PHP默认的时区是UTC,应该将 ...
- Prim算法求最大权,POJ(2485)
题目链接:http://poj.org/problem?id=2485 解题报告: 这里有一点要注意的是,第一个点时,dis数组还没有初始化,还全部为inf.第一次来到更新权时,才把邻接矩阵的数据存到 ...
- 20145238-荆玉茗 《Java程序设计》第7周学习总结
20145238 <Java程序设计>第7周学习总结 教材学习内容总结 第13章时间与日期 13.1.1 ·即使标注为GMT(格林威治时间),实际上谈到的的是UTC(Unix时间)时间. ...
- python_4_interaction
#1(方法1)尽量不用这种拼接法,效率低下,占用内存多 name=input("name:") age=input('age:') job=input('job:') salary ...
- Thread 创建线程
1.该线程变量 无参数 我们可以把线程的变量 理解为一个 委托.可以指向一个方法.有点像c语言中的指向函数的指针. 第1步我们创建了 Thread变量t1 ,第2步创建了一个方法threadChild ...