python并发编程之Queue线程、进程、协程通信(五)
单线程、多线程之间、进程之间、协程之间很多时候需要协同完成工作,这个时候它们需要进行通讯。或者说为了解耦,普遍采用Queue,生产消费模式。
系列文章
同步deque和多线程Queue
程序有时需要在列表的端点进行操作,比list更加优化的数据结构有Queue和deque。
deque
deque一般用在定长队列,多余的数据会被丢弃,这个队列是线程非安全的。
from queue import Queue, deque
# 大于会截取后面的一段
q = deque(iterable=[1,2,3,4], maxlen=5)
# 参数iterable可以是任何可迭代对象,maxlen代表定长
# 添加与取出
q.append(3) # 从尾部添加
q.pop() # 从尾部弹出一个
q.appendleft(4) # 从首部添加
q.popleft() # 从首部弹出
q.clear() # 清空队列
q.extend([1, 3, 3]) # 将原来的队列从右侧扩展
q.extendleft() # 将原来的队列从左侧扩展
q.insert(2, 3) # 在索引为2的位置插入3,如果队列已达到最大,抛出异常
# 复制
q1 = q.copy() # 完全符合一份队列
# 统计
n = q.count(3) # 统计某个值的数目
x = q.index(3) # 查找某个值的位置
# 变换
q.reverse() # 将原来的q翻转
q.remove(3) # 删除队列中的所有的3
q.rotate(2) # 向右旋转两步
Queue
Queue提供更加完整成熟的队列操作,相对于deque来说偏重型,他是线程安全的队列。
- 方法和属性分析
from queue import Queue, deque
q = Queue(maxsize=5) #maxsize<=0,队列长度没有限制,这个Queue是线程安全的,通过锁机制保证
print(q.queue) # 一个deque队列
print(q.mutex) # 队列的线程锁
print(q.not_empty) # 非空通知,用在多线程
print(q.not_full) # 非满通知,用在多线程
print(q.all_tasks_done) # 完成的任务
print(q.maxsize)
print(q.unfinished_tasks) # 队列未完成的任务数量,即队列目前的数目
# 数据存取
q.put(3, block=True, timeout=3) # 向队列左边添加数据,block为True队列满了阻塞等待,block为false则直接抛出异常
q.get(block=True, timeout=3) # 队列取出数据,超时抛出异常,block为false忽略timeout
# q.get_nowait() # 立即获取,没有抛出异常
q.put_nowait(4) # 立即插入,已满抛出异常
# 判断
q.full() # 判断当前队列是否已满,满了返回True
q.empty() # 判断当前队列是否为空,空返回True
# 统计
q.task_done() # 用来通知队列任务完成
q.qsize() # 当前队列的任务数量,不绝对可靠
q.join() # 阻塞直到所有的任务完成,即q.unfinished_tasks降为0
- 实例
from threading import Thread
from queue import Queue, deque
import time
def get_from_queue(queue:Queue):
while True:
if not queue.empty():
print(queue.get_nowait())
queue.task_done() # 任务完成
def put_to_queue(queue:Queue):
for i in range(100):
if not queue.full():
queue.put_nowait(i)
else:
time.sleep(0.1)
q = Queue(5)
th1 = Thread(target=get_from_queue, args=(q,))
th2 = Thread(target=put_to_queue, args=(q,))
th1.start()
th2.start()
进程间通讯
multiprocessing的Queue对象可以作为进程间通讯的第三者。
from multiprocessing import Queue, Process, Pool
import time
def get_from_queue(queue:Queue):
while True:
if not queue.empty():
print(queue.get_nowait())
def put_to_queue(queue:Queue):
for i in range(100):
if not queue.full():
queue.put_nowait(i)
else:
time.sleep(0.1)
if __name__ == '__main__':
q = Queue(9) # 这个Queue可以在多个进程之间共享
p1 = Process(target=get_from_queue, args=(q,))
p2 = Process(target=put_to_queue, args=(q,))
p1.start()
p2.start()
multiprocessing.Queue对象
Queue对象的大部分方法和Queue.Queue的方法相同,用法也一样,但有几个特殊的方法:
q = Queue(9) # 这个Queue可以在多个进程之间共享
# q.close() # 关闭队列,不再接收数据
# q.cancel_join_thread() # 取消阻塞等待
q.join_thread() # 线程阻塞等待
gevent协程的Queue
gevent.queue.Queue基于协程,Queue在多个协程间共享,Queue实现了迭代器协议,可以使用for循环遍历。
from gevent.queue import Queue
import gevent
import time
def get_from_queue(queue:Queue, n):
i = 0
print('start---get--{}'.format(n))
while True:
print(str(queue.get()) + 'get' + str(n))
i += 1
if i == 100:
break
def put_to_queue(queue:Queue, n):
i = 0
print('start---put--{}'.format(n))
while True:
queue.put(i)
print(str(i) + 'put' + str(n))
i += 1
if i == 100:
break
if __name__ == '__main__':
q = Queue(9) # 这个Queue可以在多个进程之间共享
job1 = [gevent.spawn(put_to_queue, q,i) for i in range(2)]
job2 = [gevent.spawn(get_from_queue, q,i) for i in range(2)]
job1.extend(job2)
gevent.joinall(job1)
协程启动后会按照添加到循环的顺序开始执行,上例在队列未满之前一直执行put操作,直到队列满后阻塞就切换到put2协程,也会立即阻塞,然后切换到get1协程,获取所有的值直到队列为空后阻塞切换。
gevent.queue.Queue对象
其方法基本和Queue.Queue的方法相同,特殊方法如下:
q = Queue(9, items=[1,2,3, StopIteration]) # 实现迭代协议,最后一个必须是StopIteration
# q.copy() #复制一个队列
x = q.next() # 唤醒获取值
q.peek(block=True, timeout=None) # 获取一个值但是不删除它
q.peek_nowait() # 立即获取,忽略timeout
q.put() # 会唤醒多个协程完成添加操作
q.get() # 会挂起多个协程
gevent.queue.JoinableQueue对象扩展了Queue的功能,添加了task_done和join方法。
q = JoinableQueue(9, items=[1,2,3, StopIteration]) # 这个Queue可以在多个进程之间共享
q.task_done() # 通知队列一个任务完成
q.unfinished_tasks # 未完成的任务计数
q.join() # 阻塞等待任务完成,如果unfinished_tasks降为0,则解除
- 实例
from gevent.queue import Queue, JoinableQueue
import gevent
import time
def get_from_queue(queue:JoinableQueue):
while True:
try:
x = queue.get() # 阻塞时就会切换协程
print(x)
finally:
queue.task_done()
if __name__ == '__main__':
q = JoinableQueue(8)
job1 = [gevent.spawn(get_from_queue, q) for i in range(2)]
for i in range(100):
q.put(i) # 当Put被阻塞时将切换协程,
q.join() # 如果不等待的话,最后一次put后将直接退出
python并发编程之Queue线程、进程、协程通信(五)的更多相关文章
- python并发编程之threading线程(一)
进程是系统进行资源分配最小单元,线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.进程在执行过程中拥有独立的内存单元,而多个线程共享内存等资源. 系列文章 py ...
- python并发编程之gevent协程(四)
协程的含义就不再提,在py2和py3的早期版本中,python协程的主流实现方法是使用gevent模块.由于协程对于操作系统是无感知的,所以其切换需要程序员自己去完成. 系列文章 python并发编程 ...
- python并发编程之asyncio协程(三)
协程实现了在单线程下的并发,每个协程共享线程的几乎所有的资源,除了协程自己私有的上下文栈:协程的切换属于程序级别的切换,对于操作系统来说是无感知的,因此切换速度更快.开销更小.效率更高,在有多IO操作 ...
- python并发编程之multiprocessing进程(二)
python的multiprocessing模块是用来创建多进程的,下面对multiprocessing总结一下使用记录. 系列文章 python并发编程之threading线程(一) python并 ...
- Python并发编程二(多线程、协程、IO模型)
1.python并发编程之多线程(理论) 1.1线程概念 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程 线程顾名思义,就是一条流水线工作的过程(流水线的工作需要电源,电源就相当于 ...
- 学到了林海峰,武沛齐讲的Day34 完 线程 进程 协程 很重要
线程 进程 协程 很重要 ...儿子满月回家办酒,学的有点慢,坚持
- Python学习笔记整理总结【网络编程】【线程/进程/协程/IO多路模型/select/poll/epoll/selector】
一.socket(单链接) 1.socket:应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socke ...
- Python核心技术与实战——十七|Python并发编程之Futures
不论是哪一种语言,并发编程都是一项非常重要的技巧.比如我们上一章用的爬虫,就被广泛用在工业的各个领域.我们每天在各个网站.App上获取的新闻信息,很大一部分都是通过并发编程版本的爬虫获得的. 正确并合 ...
- 文成小盆友python-num11-(1) 线程 进程 协程
本节主要内容 线程补充 进程 协程 一.线程补充 1.两种使用方法 这里主要涉及两种使用方法,一种为直接使用,一种为定义自己的类然后继承使用如下: 直接使用如下: import threading d ...
随机推荐
- 【.Net】C#获取Windows系统特殊文件夹的路径
系统特殊文件夹是包含公共信息的文件夹,如“Program Files”.“Programs”.“System”或“Startup”.特殊文件夹在默认情况下由系统设置,或者由用户在安装 Windows ...
- UVALive6434_Number Assignment
简单dp题. 这样的,意思为给你n个数,要你现在将这n个数分为m组,使得所有组内最大值与最小值的差的和最小. 其实可以这样来考虑这个问题,首先可以把所有的数字从小到大排个序,显然如果有一种取法是最优的 ...
- BZOJ3566 SHOI2014概率充电器(动态规划+概率期望)
设f[i]为i在子树内不与充电点连通的概率.则f[i]=(1-pi)·∏(1-qk+qk·f[k]). 然后从父亲更新答案.则f[i]=f[i]·(1-qfa+qfa*f[fa]/(1-qfa+qfa ...
- Redis安装配置及使用详解
1. 简介-两个程序通信,除了socket就是文件了,但是通过磁盘效率太低了,之前的RabbitMQ只是实现了消息的传递,现在要是实现数据的共享(一份数据,可供多人查阅),可以通过缓存实现,一个中间商 ...
- 【刷题】BZOJ 2152 聪聪可可
Description 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)--遇到这种问题,一般情况下石头剪刀布就好 ...
- CF878C Tournament set 图论
题面 题面 题解 如果2个人可以互相战胜,那么我们连一条无向边,于是最后会剩下t个联通块,其中每对联通块之间都有严格的大小关系(a.max < b.min),因此我们每插入一个点就相当于合并一段 ...
- 洛谷 P4585 [FJOI2015]火星商店问题 解题报告
P4585 [FJOI2015]火星商店问题 题目描述 火星上的一条商业街里按照商店的编号\(1,2,\dots,n\) ,依次排列着\(n\)个商店.商店里出售的琳琅满目的商品中,每种商品都用一个非 ...
- bzoj4010: [HNOI2015]菜肴制作(拓扑排序+贪心+堆)
这题不是求最小字典序...撕烤了半个小时才发现不对劲T T 这题是能让小的尽量前就尽量前,无论字典序...比如1能在2前面就一定要在2前面... 显然是要先拓扑排序,让小的尽量前转化成让大的尽量往后丢 ...
- yd的拔钉子之路之 POI 2017
写在前面的一些话 如果我NOIP没退役,这大概会写成一个系列吧,所以这算是系列的开始,要写一些奇怪的东西? 首先解释下什么叫“拔钉子”,其实就是在钉子上做题嘛......至于钉子具体是个什么东西就当面 ...
- OpenCV C++如何使RGB图像变为灰度图像
http://m.blog.csdn.net/blog/u014395105/41308979 最近在研究如何用C++来处理图像,而不使用封装好的OpenCV代码,这样能够更好的了解OpenCV的内部 ...