参考链接:https://docs.python.org/zh-cn/3.8/
目录
第一部分queue模块:
class queue.Queue(maxsize=0)
class queue.LifoQueue(maxsize=0)
class queue.PriorityQueue(maxsize=0)
class queue.SimpleQueue
Queue对象:
SimpleQueue 对象:
queue使用:
第二部分multiprocessing.queue模块
class multiprocessing.Queue([maxsize])
class multiprocessing.SimpleQueue
class multiprocessing.JoinableQueue([maxsize])
multiprocessing.Queue对象常用方法:
multiprocessing.Pipe()的用法:
第三部分asyncio.Queue模块:
类asyncio.Queue(maxsize = 0,*,loop = None )
类asyncio.PriorityQueue
类asyncio.LifoQueue
第四部分collections.deque模块:
总结:
队列可以并发的派多个线程,对排列的线程处理,并切每个需要处理线程只需要将请求的数据放入队列容器的内存中,线程不需要等待,当排列完毕处理完数据后,线程在准时来取数据即可。请求数据的线程只与这个队列容器存在关系,处理数据的线程down掉不会影响到请求数据的线程,队列会派给其他线程处理这分数据,它实现了解耦,提高效率。队列内会有一个有顺序的容器,列表与这个容器是有区别的,列表中数据虽然是排列的,但数据被取走后还会保留,而队列中这个容器的数据被取后将不会保留。当必须在多个线程之间安全地交换信息时,队列在线程编程中特别有用。
queue
模块实现多生产者,多消费者队列。当信息必须安全的在多线程之间交换时,它在线程编程中是特别有用的。此模块中的 Queue
类实现了所有锁定需求的语义。它依赖于Python支持的线程可用性.
模块实现了三种类型的队列,它们的区别仅仅是条目取回的顺序。在 FIFO 队列中,先添加的任务先取回。在 LIFO 队列中,最近被添加的条目先取回(操作类似一个堆栈)。优先级队列中,条目将保持排序( 使用 heapq模块 ) 并且最小值的条目第一个返回。
queue.
Queue
(maxsize=0)先进先出队列
FIFO队列的构造函数。maxsize是一个整数,它设置可放置在队列中的项数的上限。一旦达到这个大小,插入将阻塞,直到队列项被消耗。如果maxsize小于或等于0,则队列大小是无限的。
queue.
LifoQueue
(maxsize=0)后进先出队列
LIFO 队列构造函数。 maxsize 是个整数,用于设置可以放入队列中的项目数的上限。当达到这个大小的时候,插入操作将阻塞至队列中的项目被消费掉。如果 maxsize 小于等于零,队列尺寸为无限大。
queue.
PriorityQueue
(maxsize=0)可以设置优先级的队列,优先级数越小等级越高
优先级队列构造函数。 maxsize 是个整数,用于设置可以放入队列中的项目数的上限。当达到这个大小的时候,插入操作将阻塞至队列中的项目被消费掉。如果 maxsize 小于等于零,队列尺寸为无限大。
最小值先被取出( 最小值条目是由 sorted(list(entries))[0]
返回的条目)。条目的典型模式是一个以下形式的元组: (priority_number, data)
。
queue.
SimpleQueue
无界的 FIFO 队列构造函数。简单的队列,缺少任务跟踪等高级功能。
Queue. qsize () |
返回队列的大致大小。注意,qsize() > 0 不保证后续的 get() 不被阻塞,qsize() < maxsize 也不保证 put() 不被阻塞 |
Queue. empty () |
如果队列为空,返回 True ,否则返回 False 。如果 empty() 返回 True ,不保证后续调用的 put() 不被阻塞。类似的,如果 empty() 返回 False ,也不保证后续调用的 get() 不被阻塞。 |
Queue. full () |
如果队列是满的返回 True ,否则返回 False 。如果 full() 返回 True 不保证后续调用的 get() 不被阻塞。类似的,如果 full() 返回 False 也不保证后续调用的 put() 不被阻塞。 |
Queue. put (item, block=True, timeout=None) |
将 item 放入队列。如果可选参数 block 是 true 并且 timeout 是 None (默认),则在必要时阻塞至有空闲插槽可用。如果 timeout 是个正数,将最多阻塞 timeout 秒,如果在这段时间没有可用的空闲插槽,将引发 Full 异常。反之 (block 是 false),如果空闲插槽立即可用,则把 item 放入队列,否则引发 Full 异常 ( 在这种情况下,timeout 将被忽略)。 |
Queue. put_nowait (item) |
相当于 put(item, False) 。 |
Queue. get (block=True, timeout=None) |
从队列中移除并返回一个项目。如果可选参数 block 是 true 并且 timeout 是 None (默认值),则在必要时阻塞至项目可得到。如果 timeout 是个正数,将最多阻塞 timeout 秒,如果在这段时间内项目不能得到,将引发 Empty 异常。反之 (block 是 false) , 如果一个项目立即可得到,则返回一个项目,否则引发 Empty 异常 (这种情况下,timeout 将被忽略)。 |
Queue. get_nowait () |
相当于 get(False) 。 |
Queue. task_done () |
表示前面排队的任务已经被完成。被队列的消费者线程使用。每个 如果 如果被调用的次数多于放入队列中的项目数量,将引发 |
Queue. join () |
表示前面排队的任务已经被完成。被队列的消费者线程使用。每个 如果 如果被调用的次数多于放入队列中的项目数量,将引发 |
SimpleQueue. qsize () |
返回队列的大致大小。注意,qsize() > 0 不保证后续的 get() 不被阻塞。 |
SimpleQueue. empty () |
如果队列为空,返回 True ,否则返回 False 。如果 empty() 返回 False ,不保证后续调用的 get() 不被阻塞。 |
SimpleQueue. put (item, block=True, timeout=None) |
将 item 放入队列。此方法永不阻塞,始终成功(除了潜在的低级错误,例如内存分配失败)。可选参数 block和 timeout 仅仅是为了保持
CPython实现细节:这个方法有一个可重入的C实现。也就是说,一个put()或get()调用可以被同一线程中的另一个put()调用中断,而不会死锁或破坏队列内的内部状态。这使得它适合在析构函数中使用,比如其他的del__方法或weakref回调。 |
SimpleQueue. put_nowait (item) |
相当于 put(item) ,仅为保持 Queue.put_nowait() 兼容性而提供 |
SimpleQueue. get (block=True, timeout=None) |
从队列中移除并返回一个项目。如果可选参数 block 是 true 并且 timeout 是 None (默认值),则在必要时阻塞至项目可得到。如果 timeout 是个正数,将最多阻塞 timeout 秒,如果在这段时间内项目不能得到,将引发 Empty 异常。反之 (block 是 false) , 如果一个项目立即可得到,则返回一个项目,否则引发 Empty 异常 (这种情况下,timeout 将被忽略)。 |
SimpleQueue. get_nowait () |
相当于 get(False) 。 |
1、queue.Queue
import queue
import threading
q = queue.Queue(maxsize=20)
for x in list(range(10)):
# 写入队列数据
q.put(x)
# 输出当前队列所有数据
# print(q.queue)
# deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
def tx(q):
while True:
# 删除队列数据,并返回该数据
if q.empty():
break
data = q.get()
print(f'{data}>>>{threading.current_thread()}')
q.task_done()
# print(q.queue)
work1 = threading.Thread(target=tx, args=(q,))
work2 = threading.Thread(target=tx, args=(q,))
work1.start()
work2.start()
q.join()
2、queue.LifoQueue
q2 = queue.LifoQueue()
for x in range(10):
# 写入队列数据
q2.put(x)
# 输出当前队列所有数据
# print(q.queue)
# deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
def tx(q):
while True:
# 删除队列数据,并返回该数据
if q2.empty():
break
data = q2.get()
print(f'{data}>>>{threading.current_thread()}')
q2.task_done()
# print(q.queue)
work3 = threading.Thread(target=tx, args=(q2,))
work4 = threading.Thread(target=tx, args=(q2,))
work3.start()
work4.start()
q.join()
queue.PriorityQueue()
q3 = queue.PriorityQueue()
for x in range(10):
# 写入队列数据
q3.put((x, x+10))
# 输出当前队列所有数据
# print(q.queue)
# deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
def tx(q):
while True:
# 删除队列数据,并返回该数据
if q3.empty():
break
data = q3.get()
print(f'{data}>>>{threading.current_thread()}')
q3.task_done()
# print(q.queue)
work3 = threading.Thread(target=tx, args=(q3,))
work4 = threading.Thread(target=tx, args=(q3,))
work3.start()
work4.start()
q3.join()
模块
一个用于多进程上下文的队列类而不是多线程.multiprocessing提供了三种队列,分别是Queue、SimpleQueue、JoinableQueue
multiprocessing.
Queue
([maxsize])返回一个使用一个管道和少量锁和信号量实现的共享队列实例。当一个进程将一个对象放进队列中时,一个写入线程会启动并将对象从缓冲区写入管道中。
一旦超时,将抛出标准库 queue
模块中常见的异常 queue.Empty
和 queue.Full
。
除了 task_done()
和 join()
之外,Queue
实现了标准库类 queue.Queue
中所有的方法
multiprocessing.
SimpleQueue
这是一个简化的 Queue
类的实现,很像带锁的 Pipe
。
empty
()
如果队列为空返回 True
,否则返回 False
。
get
()
从队列中移出并返回一个对象。
put
(item)
将 item 放入队列。
multiprocessing.
JoinableQueue
([maxsize])JoinableQueue
类是 Queue
的子类,额外添加了 task_done()
和 join()
方法。
task_done
()
指出之前进入队列的任务已经完成。由队列的消费者进程使用。对于每次调用 get()
获取的任务,执行完成后调用 task_done()
告诉队列该任务已经处理完成。
如果 join()
方法正在阻塞之中,该方法会在所有对象都被处理完的时候返回 (即对之前使用 put()
放进队列中的所有对象都已经返回了对应的 task_done()
) 。
如果被调用的次数多于放入队列中的项目数量,将引发 ValueError
异常 。
join
()
阻塞至队列中所有的元素都被接收和处理完毕。
当条目添加到队列的时候,未完成任务的计数就会增加。每当消费者进程调用 task_done()
表示这个条目已经被回收,该条目所有工作已经完成,未完成计数就会减少。当未完成计数降到零的时候, join()
阻塞被解除。
multiprocessing.Queue对象常用方法:
qsize () |
返回队列的大致长度。由于多线程或者多进程的上下文,这个数字是不可靠的。 注意,在 Unix 平台上,例如 Mac OS X ,这个方法可能会抛出 |
empty () |
如果队列是空的,返回 True ,反之返回 False 。 由于多线程或多进程的环境,该状态是不可靠的 |
full () |
如果队列是满的,返回 True ,反之返回 False 。 由于多线程或多进程的环境,该状态是不可靠的。 |
put (obj[, block[, timeout]]) |
将 obj 放入队列。如果可选参数 block 是 在 3.8 版更改: 如果队列已经关闭,会抛出 |
put_nowait (obj) |
相当于 put(obj, False) 。 |
get ([block[, timeout]]) |
从队列中取出并返回对象。如果可选参数 block 是 在 3.8 版更改: 如果队列已经关闭,会抛出 |
get_nowait () |
相当于
|
close () |
指示当前进程将不会再往队列中放入对象。一旦所有缓冲区中的数据被写入管道之后,后台的线程会退出。这个方法在队列被gc回收时会自动调用。 |
join_thread () |
等待后台线程。这个方法仅在调用了 默认情况下,如果一个不是队列创建者的进程试图退出,它会尝试等待这个队列的后台线程。这个进程可以使用 |
cancel_join_thread () |
防止 可能这个方法称为” |
使用多进程时,一般使用消息机制实现进程间通信,尽可能避免使用同步原语,例如锁。
消息机制包含: Pipe()
(可以用于在两个进程间传递消息),以及队列(能够在多个生产者和消费者之间通信)。
from multiprocessing import Process, Pipe
def send(pipe):
pipe.send(['spam'] + [42, 'egg'])
pipe.close()
def talk(pipe):
pipe.send(dict(name = 'Bob', spam = 42))
reply = pipe.recv()
print('talker got:', reply)
if __name__ == '__main__':
(con1, con2) = Pipe()
sender = Process(target = send, name = 'send', args = (con1, ))
sender.start()
child = Process(target = talk, name = 'talk', args = (con2,))
child.start()
asyncio.
Queue
(maxsize = 0,*,loop = None )先进先出(FIFO)队列。
如果maxsize小于或等于零,则队列大小为无限。如果它是一个大于的整数0
,则 在队列达到maxsize时阻塞, 直到使用删除一个项目为止。await put()
get()
与标准库线程不同queue
,队列的大小始终是已知的,可以通过调用该qsize()
方法来返回 。
:自3.8版本弃用,将在3.10版本中移除的循环参数。
此类不是线程安全的。
maxsize
队列中允许的项目数。
empty
()
True
如果队列为空,False
则返回,否则返回。
full
()
True
如果maxsize
队列中有项目,则返回。
如果使用maxsize=0
(默认值)初始化了队列,则full()
永远不会返回True
。
协程get
()
从队列中删除并返回一个项目。如果队列为空,请等待直到有一个项目可用。
get_nowait
()
如果有货马上退货,否则退货 QueueEmpty
。
协程join
()
阻塞直到队列中的所有项目都已接收并处理。
每当将项目添加到队列时,未完成任务的数量就会增加。每当消费者协程调用task_done()
以指示该物品已被检索并且所有工作完成时,计数都会减少 。当未完成的任务数降至零时,join()
取消阻止。
协程put
(item )
将项目放入队列。如果队列已满,请等到空闲插槽可用后再添加项目。
put_nowait
(项目)
将项目放入队列而不会阻塞。
如果没有立即可用的空闲插槽,请升高QueueFull
。
qsize
()
返回队列中的项目数。
task_done
()
表示先前排队的任务已完成。
由队列使用者使用。对于get()
用于提取任务的每个任务,后续调用task_done()
告诉队列该任务的处理已完成。
如果a join()
当前正在阻塞,则将在处理 完所有项目后恢复(这意味着task_done()
已收到put()
队列中每个项目的呼叫)。
ValueError
如果被调用的次数超过队列中放置的项目的次数,则引发该事件。
优先队列
asyncio.
PriorityQueue
Queue
; 的变体; 以优先级顺序检索条目(从低到低)。
条目通常是形式的元组 。(priority_number, data)
LIFO队列
asyncio.
LifoQueue
它的一个变体Queue
首先检索最新添加的条目(后进先出)。
异常
异常asyncio.
QueueEmpty
get_nowait()
在空队列上调用该方法时,将引发此异常。
异常asyncio.
QueueFull
put_nowait()
在已达到其maxsize的队列上调用该方法时引发异常。
例子
队列可用于在多个并发任务之间分配工作负载:
import asyncio
import random
import time
async def worker(name, queue):
while True:
# Get a "work item" out of the queue.
sleep_for = await queue.get()
# Sleep for the "sleep_for" seconds.
await asyncio.sleep(sleep_for)
# Notify the queue that the "work item" has been processed.
queue.task_done()
print(f'{name} has slept for {sleep_for:.2f} seconds')
async def main():
# Create a queue that we will use to store our "workload".
queue = asyncio.Queue()
# Generate random timings and put them into the queue.
total_sleep_time = 0
for _ in range(20):
sleep_for = random.uniform(0.05, 1.0)
total_sleep_time += sleep_for
queue.put_nowait(sleep_for)
# Create three worker tasks to process the queue concurrently.
tasks = []
for i in range(3):
task = asyncio.create_task(worker(f'worker-{i}', queue))
tasks.append(task)
# Wait until the queue is fully processed.
started_at = time.monotonic()
await queue.join()
total_slept_for = time.monotonic() - started_at
# Cancel our worker tasks.
for task in tasks:
task.cancel()
# Wait until all worker tasks are cancelled.
await asyncio.gather(*tasks, return_exceptions=True)
print('====')
print(f'3 workers slept in parallel for {total_slept_for:.2f} seconds')
print(f'total expected sleep time: {total_sleep_time:.2f} seconds')
asyncio.run(main())
参考链接:https://docs.python.org/3.8/library/collections.html#collections.deque
deque 是一个双端队列, 如果要经常从两端append 的数据, 选择这个数据结构就比较好了, 如果要实现随机访问,不建议用这个,请用列表.
deque 优势就是可以从两边append ,appendleft 数据. 这一点list 是没有的.
deque也支持in操作符如下写法:
q = collections.deque([0,1, 2, 3, 4])
print(100 in q) # False
print(1 in q) # True
from collections import deque
# 可以指定 队列的长度
dq = deque(maxlen=100)
# 默认从右边加入
dq.append(100)
dq.append(200)
print(dq)
# 也可以从左边加入
dq.appendleft('a')
dq.appendleft('b')
print(dq)
# 也可以加入一个列表,默认从右边加入
list1 = range(10)
dq.extend(list1)
print(dq)
# 出队列,返回出队列的元素
# 可以从左边也可以从右边 出队列
print(dq.pop())
print(dq.popleft())
# 查看 队列里面元素个数
print(len(dq))
# 统计元素的个数
#统计a 有几个
print(dq.count('a'))
# 在某个位置insert 一个元素
dq.insert(3, '大威天龙')
print(dq)
# 反转队列
dq.reverse()
print(dq)
# remove 移除某个元素(不是索引!!!!)
dq.remove(8)
print(dq)
# 清空队列元素 clear
# dq.clear()
# print(dq)
# copy 浅拷贝
dq1=dq.count()
ollections.deque在数据结构层面实现了队列,但是并没有应用场景方面的支持。
queue模块实现了面向多生产线程、多消费线程的队列。
asyncio.queue模块则实现了面向多生产协程、多消费协程的队列。
multiprocessing.queue模块实现了面向多成产进程、多消费进程的队列。