理解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)数据结构.因为它是线程安全的,所以多个线程很轻松地使用同一个实例. 源码分析 先从初始化的函数来看: 从这初始化函数能得到哪些信息呢?首 ...
随机推荐
- Struts2_总结
还未学习的内容,如果到时候要用到,再去学.1.Lamda 表达式(很复杂,很少用)2.验证框架(默认验证方法 validation.方法开始前验证.开始后验证)3.UI标签(用的不多)4.类型转换中的 ...
- Yii2.0 安装yii2-queue并在Linux启动守护进程监听消息
一.什么是yii2-queue? Yii2-queue是Yii2.0 PHP框架下一个消息队列拓展插件,支持基于DB, Redis, RabbitMQ, AMQP, Beanstalk 和 Gearm ...
- [topcoder]TheConsecutiveIntegersDivOne
http://community.topcoder.com/stat?c=problem_statement&pm=13625&rd=16278 首先,如果记得曼哈顿距离最小值那个问题 ...
- 金庸的武侠世界和SAP的江湖
2018年10月30日晚,成都地铁一号线,Jerry手机app上突然弹出来一条金庸去世的新闻. Jerry识字很早,小学一年级就开始蹭我父亲的<射雕英雄传>看了.小时候,我爸工作的车间里有 ...
- 关于tcp的keepalive
先记录几个要点 只能用在面向连接的tcp中,对应对端的非正常关闭有效(对端服务器重启这种,也是正常关闭,FIN RST包都算) 只要是写入到缓冲区就认为OK,所以UDP不适合,所以如果有正常的网络交互 ...
- UVA 11983 Weird Advertisement
题意:求矩形覆盖k次以上的区域总面积. 因为k≤10,可以在线段树上维护覆盖次数为0,...,k, ≥k的长度数量. 然后就是一个离散化以后扫描线的问题了. 离散化用的是半开半闭区间,以方便表示没有被 ...
- Robin-Karp algorithm 字符串的匹配
有关字符串的匹配问题,有很好的算法,即KMP算法,但是还有一种其实经常使用到的算法是Rabin-Karp算法,它是使用hash的原理来进行字符串匹配的.具体的做法如下. Rabin-Karp算法是由R ...
- 剑指offer28 字符串的排列
1.全局变量可以在最后去定义并初始化,不一定非要在开头 2.此题有一种特殊情况需要考虑,比如字符串是“aa”,那输出应该是“aa”,而不是“aa,aa”,即相同的不输出.实现这个处理用了c++中的容器 ...
- 卷积神经网络CNN在自然语言处理的应用
摘要:CNN作为当今绝大多数计算机视觉系统的核心技术,在图像分类领域做出了巨大贡献.本文从计算机视觉的用例开始,介绍CNN及其在自然语言处理中的优势和发挥的作用. 当我们听到卷积神经网络(Convol ...
- Vue路由讲解
1>router-link和router-view组件 2>路由配置 a.动态路由 import Home from "@/views/Home.vue"; expor ...