当使用 asyncio.create_task(function1)
和 asyncio.create_task(function2)
时,你正在创建两个将在同一个事件循环中并发运行的异步任务。这些任务运行是否高效取决于它们本身的性质。
理解异步任务
如果 function1
和 function2
是异步函数(即,它们使用了 async def
并包含 await
语句),只要这些函数执行的是非阻塞操作,比如:
- 网络 I/O
- 磁盘 I/O
- 定时器(例如
await asyncio.sleep()
) - 其他异步操作
在这种情况下,asyncio
会处理调度,在任务等待 I/O 操作完成时暂停它们,并在操作就绪时恢复它们。这就实现了高效的并发。
阻塞代码的低效性
如果 function1
和 function2
包含阻塞操作(例如 CPU 密集型任务,time.sleep()
或阻塞 I/O),它们将无法高效运行。阻塞代码会阻塞整个事件循环,防止其他任务并发运行。
高效异步任务示例
以下是一个使用 asyncio.create_task()
高效运行非阻塞异步任务的示例:
import asyncioasync def function1():print('Function 1: Start')await asyncio.sleep(2) # 模拟非阻塞 I/Oprint('Function 1: End')async def function2():print('Function 2: Start')await asyncio.sleep(3) # 模拟非阻塞 I/Oprint('Function 2: End')async def main():# 创建任务以并发运行它们task1 = asyncio.create_task(function1())task2 = asyncio.create_task(function2())# 如果你想等待它们完成,可以选择性地 await 这些任务await task1await task2# 运行主异步函数
asyncio.run(main())
使用执行器处理阻塞代码
如果需要运行阻塞 I/O 任务,应该将它们卸载到线程或进程池中,以避免阻塞事件循环:
import asyncio
from concurrent.futures import ThreadPoolExecutor
import timedef blocking_io_task1():print('Blocking Task 1: Start')time.sleep(2) # 模拟阻塞 I/Oprint('Blocking Task 1: End')def blocking_io_task2():print('Blocking Task 2: Start')time.sleep(3) # 模拟阻塞 I/Oprint('Blocking Task 2: End')async def main():loop = asyncio.get_running_loop()with ThreadPoolExecutor() as pool:# 将阻塞任务卸载到线程池task1 = loop.run_in_executor(pool, blocking_io_task1)task2 = loop.run_in_executor(pool, blocking_io_task2)# 如果你需要等待它们完成,可以这么做await task1await task2# 运行主异步函数
asyncio.run(main())
总结
- 高效异步任务: 对非阻塞操作使用
async def
函数和await
语句。 - 处理阻塞代码: 使用
loop.run_in_executor
将阻塞任务卸载到线程或进程池。
通过仔细区分阻塞和非阻塞任务,可以确保使用 asyncio.create_task()
时任务高效运行。
阅读英文
hndel-aysnc-with-blocking-code
AI好书推荐
AI日新月异,再不学来不及了。但是万丈高楼拔地起,离不开良好的基础。您是否有兴趣了解人工智能的原理和实践? 不要再观望! 我们关于 AI 原则和实践的书是任何想要深入了解 AI 世界的人的完美资源。 由该领域的领先专家撰写,这本综合指南涵盖了从机器学习的基础知识到构建智能系统的高级技术的所有内容。 无论您是初学者还是经验丰富的 AI 从业者,本书都能满足您的需求。 那为什么还要等呢?
人工智能原理与实践 全面涵盖人工智能和数据科学各个重要体系经典
北大出版社,人工智能原理与实践 人工智能和数据科学从入门到精通 详解机器学习深度学习算法原理