Asyncio Queue

本文探讨了异步编程在Python中的实现,通过使用asyncio库创建了一个简单的生产者-消费者模型,展示了如何利用事件循环进行高效的任务调度。在jupyter环境中,特别介绍了nest_asyncio的使用,以解决事件循环的兼容性问题。

新的启动事件循环

import asyncio
import random
import time
import logging
from contextlib import closing

import nest_asyncio

nest_asyncio.apply( )  # 在jupyter需要这个,不然asyncio运行出错
logging.basicConfig(  # 用日志打印输出信息
    level = logging.INFO,
    format = "%(asctime)s %(process)d %(thread)d [*] %(message)s"
)


async def newsProducer(myQueue):
    while True:
        await asyncio.sleep(1)
        data = random.randint(1, 5)
        logging.info(f"将产品放入队列{data}")
        await myQueue.put(data)


async def newsConsumer(id, myQueue):
    while True:
        logging.info("消费者: {} 试图从队列中获取".format(id))
        item = await myQueue.get( )
        if item is None:
            break
        logging.info("消费者: {} 消耗了ID的商品: {}".format(id, item))


async def main( ):
    myQueue = asyncio.Queue(maxsize = 10)
    await asyncio.gather(
        newsProducer(myQueue),
        newsConsumer("A", myQueue),
        newsConsumer("B", myQueue),
    )


if __name__ == "__main__":
    # 修改了这里
    with closing(asyncio.get_event_loop( )) as loop:
        loop.run_until_complete(main( ))

旧的启动事件循环

import asyncio
import random
import time
import logging
import nest_asyncio
nest_asyncio.apply() # 在jupyter需要这个,不然asyncio运行出错
logging.basicConfig(  # 用日志打印输出信息
    level=logging.INFO,
    format="%(asctime)s %(process)d %(thread)d [*] %(message)s"
)


async def newsProducer(myQueue):
    while True:
        await asyncio.sleep(1)
        data = random.randint(1, 5)
        logging.info(f"将产品放入队列{data}")
        await myQueue.put(data)


async def newsConsumer(id, myQueue):
    while True:
        logging.info("消费者: {} 试图从队列中获取".format(id))
        item = await myQueue.get()
        if item is None:
            break
        logging.info("消费者: {} 消耗了ID的商品: {}".format(id, item))

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    myQueue = asyncio.Queue(loop=loop, maxsize=10)
    try:
        loop.run_until_complete(asyncio.gather(
            newsProducer(myQueue),
            newsConsumer("A", myQueue),
            newsConsumer("B", myQueue),
        ))
    except KeyboardInterrupt:
        asyncio.Task.all_tasks()
        asyncio.gather(*asyncio.Task.all_tasks()).cancel()
        loop.stop()
        # loop.run_forever()  # 在jupyter不能手动关闭
    finally:
        pass
        # loop.close()  # 在jupyter不能手动关闭





    2019-11-15 16:01:57,574 10912 13460 [*] 消费者: A 试图从队列中获取
    2019-11-15 16:01:57,592 10912 13460 [*] 消费者: B 试图从队列中获取
    2019-11-15 16:01:58,577 10912 13460 [*] 将产品放入队列1
    2019-11-15 16:01:58,584 10912 13460 [*] 消费者: A 消耗了ID的商品: 1
    2019-11-15 16:01:58,589 10912 13460 [*] 消费者: A 试图从队列中获取
    2019-11-15 16:01:59,580 10912 13460 [*] 将产品放入队列4
    2019-11-15 16:01:59,585 10912 13460 [*] 消费者: B 消耗了ID的商品: 4
    2019-11-15 16:01:59,590 10912 13460 [*] 消费者: B 试图从队列中获取
    2019-11-15 16:02:00,598 10912 13460 [*] 将产品放入队列1
    2019-11-15 16:02:00,604 10912 13460 [*] 消费者: A 消耗了ID的商品: 1
    2019-11-15 16:02:00,609 10912 13460 [*] 消费者: A 试图从队列中获取
    2019-11-15 16:02:01,602 10912 13460 [*] 将产品放入队列2
    2019-11-15 16:02:01,610 10912 13460 [*] 消费者: B 消耗了ID的商品: 2
    2019-11-15 16:02:01,618 10912 13460 [*] 消费者: B 试图从队列中获取
    2019-11-15 16:02:02,609 10912 13460 [*] 将产品放入队列2
    2019-11-15 16:02:02,619 10912 13460 [*] 消费者: A 消耗了ID的商品: 2
    2019-11-15 16:02:02,626 10912 13460 [*] 消费者: A 试图从队列中获取
    2019-11-15 16:02:03,618 10912 13460 [*] 将产品放入队列1
    2019-11-15 16:02:03,626 10912 13460 [*] 消费者: B 消耗了ID的商品: 1
    2019-11-15 16:02:03,631 10912 13460 [*] 消费者: B 试图从队列中获取
    2019-11-15 16:02:04,622 10912 13460 [*] 将产品放入队列5
    2019-11-15 16:02:04,628 10912 13460 [*] 消费者: A 消耗了ID的商品: 5
    2019-11-15 16:02:04,632 10912 13460 [*] 消费者: A 试图从队列中获取
    2019-11-15 16:02:05,623 10912 13460 [*] 将产品放入队列3
    2019-11-15 16:02:05,631 10912 13460 [*] 消费者: B 消耗了ID的商品: 3
    2019-11-15 16:02:05,634 10912 13460 [*] 消费者: B 试图从队列中获取
    

### Python `asyncio.Queue` 使用方法及示例 #### 什么是 `asyncio.Queue` `asyncio.Queue` 是 Python 的异步编程库 `asyncio` 提供的一个队列实现,用于在协程之间传递数据。它支持常见的队列操作,例如放入 (`put`) 和获取 (`get`) 数据项,并且这些操作都是异步的,可以在等待时释放事件循环。 #### 基本属性和方法 以下是 `asyncio.Queue` 的一些常用属性和方法[^2]: - **maxsize**: 队列的最大大小,默认为 0 表示无限制。 - **empty()**: 如果队列为空,则返回 True。 - **full()**: 如果队列为满,则返回 True。 - **get()**: 获取并移除队列中的一个项目,如果队列为空则会挂起直到有可用的数据。 - **put(item)**: 将一个项目放入队列中,如果队列已满则会挂起直到有足够的空间。 - **task_done()**: 表明之前入队的任务已完成处理。 - **join()**: 阻塞调用者,直到队列中的所有任务都完成。 #### 示例代码 下面是一个简单的生产者消费者模式的例子,展示了如何使用 `asyncio.Queue`: ```python import asyncio async def producer(queue): for i in range(5): # 生产 5 个项目 print(f'Producer is producing item {i}') await queue.put(i) # 放入队列 await asyncio.sleep(1) async def consumer(queue): while True: item = await queue.get() # 从队列获取项目 if item is None: # 结束信号 break print(f'Consumer consumed item {item}') queue.task_done() async def main(): queue = asyncio.Queue() producer_task = asyncio.create_task(producer(queue)) consumer_task = asyncio.create_task(consumer(queue)) await producer_task await queue.join() # 等待所有任务完成 # 发送结束信号给消费者 await queue.put(None) await consumer_task # 运行主函数 asyncio.run(main()) ``` 在这个例子中: - `producer` 协程负责向队列中添加数据。 - `consumer` 协程负责从队列中取出数据并消费它们。 - 主函数通过创建两个任务来运行这两个协程,并确保所有的生产和消费完成后才退出程序。 #### 注意事项 当使用 `asyncio.Queue` 时需要注意以下几点: - 当多个协程尝试访问同一个队列时,`asyncio.Queue` 自动管理同步问题。 - 可以设置最大容量 (maxsize),防止内存占用过多。 - 应该始终调用 `queue.task_done()` 来表明一项工作已经完成,这有助于配合 `queue.join()` 正确控制流程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值