【问题标题】:How to use asyncio for asynchronous handler?如何将 asyncio 用于异步处理程序?
【发布时间】:2022-12-07 01:22:51
【问题描述】:
我有一个不断产生一些对象的函数,比如说每秒 1 个,还有一个工作 2 秒并处理这些对象的处理程序。例如:
from time import sleep
import asyncio
from datetime import datetime
def generator():
i = 0
while True:
yield i
i += 1
sleep(1)
def handler(number):
sleep(2)
if number % 2 == 0:
print(str(number) + ' is even')
else:
print(str(number) + ' is odd')
for number in generator():
handler(number)
因此,例如程序启动后 6 秒打印“2 是偶数”。如何使用 asyncio 将此时间减少到 4 秒(生成器 2 秒 + 处理程序 2 秒)?我需要设置数字的异步处理。
【问题讨论】:
标签:
python
asynchronous
python-asyncio
【解决方案1】:
您需要在此处进行一些更改:
-
你的generator目前是一个“生成器”,把它改成"asynchronous generator"这样你就可以使用async for了。这样它就可以将控制权交还给事件循环。
-
在asyncio库中使用sleep的异步版本:asyncio.sleep。 time.sleep不配合其他任务。
-
将您的 handler 同步功能更改为“协程”。
import asyncio
async def generator():
i = 0
while True:
yield i
i += 1
await asyncio.sleep(1)
async def handler(number):
await asyncio.sleep(2)
if number % 2 == 0:
print(str(number) + " is even")
else:
print(str(number) + " is odd")
async def main():
async for number in generator():
asyncio.create_task(handler(number))
asyncio.run(main())
现在,您的第一个任务是main,asyncio.run() 自动将其创建为任务。然后当这个任务运行时,它通过generator()异步迭代。然后为每个数字接收值,您从 handler 协程中创建一个新任务。
这样睡眠时间就会重叠。当它等待新号码 1 秒时,它实际上也等待 handler() 1 秒。那么在收到号码的时候,handler()任务的1秒已经过去了,只需要1秒。
如果需要,您可以查看任务数:
async def main():
async for number in generator():
print(f"Number of all tasks: {len(asyncio.all_tasks())}")
asyncio.create_task(handler(number))
因为每个处理程序睡眠2秒,而您的数字生成器睡眠1秒,您会看到在每次迭代中2任务都存在于事件循环中。在generator协程中将await asyncio.sleep(1)更改为await asyncio.sleep(0.5),你会看到4任务在每次迭代中都在事件循环中。