python队列的使用及总结

       参考链接: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 模块实现多生产者,多消费者队列。当信息必须安全的在多线程之间交换时,它在线程编程中是特别有用的。此模块中的 Queue 类实现了所有锁定需求的语义。它依赖于Python支持的线程可用性.

模块实现了三种类型的队列,它们的区别仅仅是条目取回的顺序。在 FIFO 队列中,先添加的任务先取回。在 LIFO 队列中,最近被添加的条目先取回(操作类似一个堆栈)。优先级队列中,条目将保持排序( 使用 heapq模块 ) 并且最小值的条目第一个返回。

class queue.Queue(maxsize=0)

         先进先出队列

         FIFO队列的构造函数。maxsize是一个整数,它设置可放置在队列中的项数的上限。一旦达到这个大小,插入将阻塞,直到队列项被消耗。如果maxsize小于或等于0,则队列大小是无限的。

class queue.LifoQueue(maxsize=0)

         后进先出队列

        LIFO 队列构造函数。 maxsize 是个整数,用于设置可以放入队列中的项目数的上限。当达到这个大小的时候,插入操作将阻塞至队列中的项目被消费掉。如果 maxsize 小于等于零,队列尺寸为无限大。

class queue.PriorityQueue(maxsize=0)

         可以设置优先级的队列,优先级数越小等级越高   

       优先级队列构造函数。 maxsize 是个整数,用于设置可以放入队列中的项目数的上限。当达到这个大小的时候,插入操作将阻塞至队列中的项目被消费掉。如果 maxsize 小于等于零,队列尺寸为无限大。

       最小值先被取出( 最小值条目是由 sorted(list(entries))[0] 返回的条目)。条目的典型模式是一个以下形式的元组: (priority_number, data) 。

class queue.SimpleQueue

          无界的 FIFO 队列构造函数。简单的队列,缺少任务跟踪等高级功能。

 Queue对象:

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(itemblock=Truetimeout=None) 将 item 放入队列。如果可选参数 block 是 true 并且 timeout 是 None (默认),则在必要时阻塞至有空闲插槽可用。如果 timeout 是个正数,将最多阻塞 timeout 秒,如果在这段时间没有可用的空闲插槽,将引发 Full 异常。反之 (block 是 false),如果空闲插槽立即可用,则把 item 放入队列,否则引发 Full 异常 ( 在这种情况下,timeout 将被忽略)。
Queue.put_nowait(item) 相当于 put(item, False) 。
Queue.get(block=Truetimeout=None) 从队列中移除并返回一个项目。如果可选参数 block 是 true 并且 timeout 是 None (默认值),则在必要时阻塞至项目可得到。如果 timeout 是个正数,将最多阻塞 timeout 秒,如果在这段时间内项目不能得到,将引发 Empty 异常。反之 (block 是 false) , 如果一个项目立即可得到,则返回一个项目,否则引发 Empty 异常 (这种情况下,timeout 将被忽略)。
Queue.get_nowait() 相当于 get(False) 。
Queue.task_done()

表示前面排队的任务已经被完成。被队列的消费者线程使用。每个 get() 被用于获取一个任务, 后续调用 task_done() 告诉队列,该任务的处理已经完成。

如果 join() 当前正在阻塞,在所有条目都被处理后,将解除阻塞(意味着每个 put() 进队列的条目的 task_done() 都被收到)。

如果被调用的次数多于放入队列中的项目数量,将引发 ValueError 异常 。

Queue.join()

表示前面排队的任务已经被完成。被队列的消费者线程使用。每个 get() 被用于获取一个任务, 后续调用 task_done() 告诉队列,该任务的处理已经完成。

如果 join() 当前正在阻塞,在所有条目都被处理后,将解除阻塞(意味着每个 put() 进队列的条目的 task_done() 都被收到)。

如果被调用的次数多于放入队列中的项目数量,将引发 ValueError 异常 。

SimpleQueue 对象:

SimpleQueue.qsize() 返回队列的大致大小。注意,qsize() > 0 不保证后续的 get() 不被阻塞。
SimpleQueue.empty() 如果队列为空,返回 True ,否则返回 False 。如果 empty() 返回 False ,不保证后续调用的 get() 不被阻塞。
SimpleQueue.put(itemblock=Truetimeout=None)

将 item 放入队列。此方法永不阻塞,始终成功(除了潜在的低级错误,例如内存分配失败)。可选参数 block和 timeout 仅仅是为了保持 Queue.put() 的兼容性而提供,其值被忽略。

 

CPython实现细节:这个方法有一个可重入的C实现。也就是说,一个put()或get()调用可以被同一线程中的另一个put()调用中断,而不会死锁或破坏队列内的内部状态。这使得它适合在析构函数中使用,比如其他的del__方法或weakref回调。

SimpleQueue.put_nowait(item) 相当于 put(item) ,仅为保持 Queue.put_nowait() 兼容性而提供
SimpleQueue.get(block=Truetimeout=None) 从队列中移除并返回一个项目。如果可选参数 block 是 true 并且 timeout 是 None (默认值),则在必要时阻塞至项目可得到。如果 timeout 是个正数,将最多阻塞 timeout 秒,如果在这段时间内项目不能得到,将引发 Empty 异常。反之 (block 是 false) , 如果一个项目立即可得到,则返回一个项目,否则引发 Empty 异常 (这种情况下,timeout 将被忽略)。
SimpleQueue.get_nowait() 相当于 get(False) 。

queue使用:

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模块

一个用于多进程上下文的队列类而不是多线程.multiprocessing提供了三种队列,分别是Queue、SimpleQueue、JoinableQueue

class multiprocessing.Queue([maxsize])

        返回一个使用一个管道和少量锁和信号量实现的共享队列实例。当一个进程将一个对象放进队列中时,一个写入线程会启动并将对象从缓冲区写入管道中。

          一旦超时,将抛出标准库 queue 模块中常见的异常 queue.Empty 和 queue.Full

除了 task_done() 和 join() 之外,Queue  实现了标准库类 queue.Queue 中所有的方法

 

class multiprocessing.SimpleQueue

这是一个简化的 Queue 类的实现,很像带锁的 Pipe 。

empty()

如果队列为空返回 True ,否则返回 False 。

get()

从队列中移出并返回一个对象。

put(item)

将 item 放入队列。

class 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 ,这个方法可能会抛出 NotImplementedError  异常,因为该平台没有实现 sem_getvalue() 。

empty() 如果队列是空的,返回 True ,反之返回 False 。 由于多线程或多进程的环境,该状态是不可靠的
full() 如果队列是满的,返回 True ,反之返回 False 。 由于多线程或多进程的环境,该状态是不可靠的。
put(obj[, block[, timeout]])

将 obj 放入队列。如果可选参数 block 是 True (默认值) 而且 timeout 是 None (默认值), 将会阻塞当前进程,直到有空的缓冲槽。如果 timeout 是正数,将会在阻塞了最多 timeout 秒之后还是没有可用的缓冲槽时抛出 queue.Full  异常。反之 (block 是 False 时),仅当有可用缓冲槽时才放入对象,否则抛出 queue.Full 异常 (在这种情形下 timeout 参数会被忽略)。

在 3.8 版更改: 如果队列已经关闭,会抛出 ValueError 而不是 AssertionError 。

put_nowait(obj) 相当于 put(obj, False)
get([block[, timeout]])

从队列中取出并返回对象。如果可选参数 block 是 True (默认值) 而且 timeout 是 None (默认值), 将会阻塞当前进程,直到队列中出现可用的对象。如果 timeout 是正数,将会在阻塞了最多 timeout 秒之后还是没有可用的对象时抛出 queue.Empty 异常。反之 (block 是 False 时),仅当有可用对象能够取出时返回,否则抛出 queue.Empty 异常 (在这种情形下 timeout 参数会被忽略)。

在 3.8 版更改: 如果队列已经关闭,会抛出 ValueError 而不是 OSError 。

get_nowait()

相当于 get(False) 。

multiprocessing.Queue 类有一些在 queue.Queue 类中没有出现的方法。这些方法在大多数情形下并不是必须的。

close() 指示当前进程将不会再往队列中放入对象。一旦所有缓冲区中的数据被写入管道之后,后台的线程会退出。这个方法在队列被gc回收时会自动调用。
join_thread()

等待后台线程。这个方法仅在调用了 close() 方法之后可用。这会阻塞当前进程,直到后台线程退出,确保所有缓冲区中的数据都被写入管道中。

默认情况下,如果一个不是队列创建者的进程试图退出,它会尝试等待这个队列的后台线程。这个进程可以使用 cancel_join_thread() 让 join_thread() 方法什么都不做直接跳过。

cancel_join_thread()

防止 join_thread() 方法阻塞当前进程。具体而言,这防止进程退出时自动等待后台线程退出。详见 join_thread()

可能这个方法称为”allow_exit_without_flush()“ 会更好。这有可能会导致正在排队进入队列的数据丢失,大多数情况下你不需要用到这个方法,仅当你不关心底层管道中可能丢失的数据,只是希望进程能够马上退出时使用。

multiprocessing.Pipe()的用法:

         使用多进程时,一般使用消息机制实现进程间通信,尽可能避免使用同步原语,例如锁。

消息机制包含: 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模块:

asyncio.Queuemaxsize = 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()取消阻止。

协程putitem 

将项目放入队列。如果队列已满,请等到空闲插槽可用后再添加项目。

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())

第四部分collections.deque模块:

参考链接: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模块实现了面向多成产进程、多消费进程的队列。

你可能感兴趣的:(python,python)