如果你不确定有多少个任务需要执行,并且想要使用while True循环来不断地生成和执行任务,同时控制并发量,你可以使用asyncio.Queue和asyncio.create_task结合asyncio.Semaphore来实现。下面是一个例子:
python
import asyncio
import random
import time
模拟一个异步任务
async def async_task(task_id):
print(f"Starting task {task_id} at {time.strftime(‘%X’)}“)
await asyncio.sleep(random.uniform(1, 3)) # 模拟不同时长的耗时操作
print(f"Finished task {task_id} at {time.strftime(‘%X’)}”)
return task_id * 2 # 假设任务有返回值
任务生成器,使用 while True 循环来生成任务
async def task_generator(queue):
while True:
task_id = random.randint(1, 100) # 随机生成任务ID作为示例
queue.put_nowait(task_id)
await asyncio.sleep(0.5) # 每0.5秒生成一个任务
任务执行函数,使用信号量控制并发量
async def task_executor(queue, semaphore, limit):
while True:
task_id = await queue.get() # 从队列中获取任务
async with semaphore: # 使用信号量保证并发量不超过限制
result = await async_task(task_id)
print(f"Task {task_id} result: {result}")
queue.task_done() # 通知队列任务已完成
主函数
async def main():
queue = asyncio.Queue() # 创建一个队列来存放任务
semaphore = asyncio.Semaphore(5) # 创建一个信号量,限制并发量为5
limit = 5 # 并发量限制
# 创建任务生成器协程和任务执行器协程
task_gen_task = asyncio.create_task(task_generator(queue))
executors = [asyncio.create_task(task_executor(queue, semaphore, limit)) for _ in range(limit)]
try:
# 等待任务生成器协程完成(这里使用异常处理来允许主程序优雅退出)
await task_gen_task
except asyncio.CancelledError:
pass
finally:
# 停止所有任务执行器协程
for executor in executors:
executor.cancel()
await asyncio.gather(*executors, return_exceptions=True)
运行事件循环
asyncio.run(main())
在这个例子中,task_generator函数使用while True循环不断生成任务,并将任务ID放入队列中。task_executor函数从队列中获取任务,并使用信号量semaphore来确保并发量不会超过设定的限制。主函数main中创建了任务生成器的协程和任务执行器的协程列表,并等待任务生成器协程完成。当需要停止任务时,可以取消任务生成器和所有任务执行器的协程。
请注意,在实际应用中,你可能需要一种机制来优雅地停止任务生成器和任务执行器,例如监听某个信号或检查某个条件。在这个例子中,我使用了异常处理来允许主程序在取消任务生成器协程时优雅退出。此外,asyncio.gather在收集任务执行器协程的结果时使用了return_exceptions=True来确保即使有协程抛出异常也能继续收集其他协程的结果。