Python的异步编程功能 (或简称async)使您可以编写程序,而不必等待独立的任务完成,从而可以完成更多的工作。 Python随附的asyncio
库为您提供了使用异步处理磁盘或网络I / O的工具,而无需等待其他所有事情。
asyncio
提供了两种用于处理异步操作的API: 高级和低级 。 高级API是最常用的API,它们适用于最广泛的应用程序。 低级API功能强大,但也很复杂,并且使用频率较低。
[ 同样在InfoWorld上:Python异步编程入门 ]
在本文中,我们将重点介绍高级API。 在以下各节中,我们将遍历asyncio
最常用的高级API,并展示如何将它们用于涉及异步任务的常见操作。
如果您是Python异步的新手,或者可以使用它的工作原理来进行复习, 请先阅读我对Python异步的介绍,然后再深入研究。
在Python中运行协程和任务
自然,异步最常见的asyncio
是运行Python脚本的异步部分。 这意味着要学会使用协同程序和任务。
Python的异步组件(包括协程和任务)只能与其他异步组件一起使用,而不能与常规的同步Python一起使用,因此您需要asyncio
来弥合差距。 为此,请使用asyncio.run
函数:
import asyncio
async def main():
print ("Waiting 5 seconds. ")
for _ in range(5):
await asyncio.sleep(1)
print (".")
print ("Finished waiting.")
asyncio.run(main())
这将运行main()
,以及所有协程main()
触发,并等待结果返回。
通常,Python程序应仅具有一个.run()
语句,就像Python程序应仅具有一个main()
函数一样。 如果不小心使用异步,可能会使程序的控制流难以阅读。 程序的异步代码只有一个入口点,可以防止事情变得繁琐。
异步函数也可以安排为task或包装协程并帮助运行它们的对象。
async def my_task():
do_something()
task = asyncio.create_task(my_task())
然后, my_task()
在事件循环中运行,其结果存储在task
。
如果只有一个任务要从中获取结果,则可以使用asyncio.wait_for(task)
等待任务完成,然后使用task.result()
检索其结果。 但是,如果您已计划执行许多任务,并且想要等待所有任务完成,请使用asyncio.wait([task1, task2])
来收集结果。 (请注意,如果您不希望它们运行超过一定的时间长度,则可以为这些操作设置超时。)
[ 同样在InfoWorld上:6个您不想错过的Python新功能 ]
在Python中管理异步事件循环
asyncio
另一个常见用法是管理异步事件循环 。 事件循环是一个运行异步函数和回调的对象。 使用asyncio.run()
时会自动创建它。 您通常只希望每个程序仅使用一个异步事件循环,以使事情易于管理。
如果要编写更高级的软件(例如服务器),则需要对事件循环的较低级别的访问。 为此,您可以“揭开面纱”并直接使用事件循环的内部构件 。 但是对于简单的工作,则不需要。
在Python中使用流读取和写入数据
异步的最佳方案是长时间运行的网络操作,在这种情况下,应用程序可能会阻止等待其他资源返回结果。 为此, asyncio
提供了stream ,它们是用于执行网络I / O的高级机制。 这包括充当网络请求的服务器。
asyncio
使用两个类StreamReader
和StreamWriter
,从高层进行网络读写。 如果要从网络读取,则可以使用asyncio.open_connection()
打开连接。 该函数返回一个StreamReader
和StreamWriter
对象的元组,并且您将在每个方法上使用.read()
和.write()
方法进行通信。
要从远程主机接收连接,请使用asyncio.start_server()
。 asyncio.start_server()
函数将回调函数client_connected_cb
作为参数,该回调函数在接收到请求时就会被调用。 该回调函数将StreamReader
和StreamWriter
实例作为参数,因此您可以处理服务器的读/写逻辑。 ( 有关使用asyncio
驱动的aiohttp
库的简单HTTP服务器的示例, 请参见此处 。)
[ 不要错过InfoWorld的2020年度技术奖获奖者:年度最佳软件开发,云计算,数据分析和机器学习产品 ]
在Python中同步任务
异步任务倾向于独立运行,但是有时您希望它们彼此通信。 asyncio
提供了队列和其他几种在任务之间进行同步的机制:
- 队列 :
asyncio
队列允许异步函数来排队Python对象被其他异步功能消耗-例如,对不同类型的基于它们的行为功能之间分配工作负荷。 - 同步原语 :
asyncio
锁,事件,条件和信号灯的工作方式与常规Python相对应。
所有这些方法要记住的一件事是它们不是线程安全的。 对于在同一事件循环中运行的异步任务,这不是问题。 但是,如果您尝试与其他事件循环,OS线程或进程中的任务共享信息,则需要使用threading
模块及其对象来执行此操作。
此外,如果要跨线程边界启动协程,请使用asyncio.run_coroutine_threadsafe()
函数,并将事件循环作为参数传递给它。
在Python中暂停协程
asyncio
另一种常见用法以及讨论不足的一种asyncio
是在协程内部等待任意任意时间长度。 您不能为此使用time.sleep()
,否则将阻止整个程序。 而是使用asyncio.sleep()
,它允许其他协程继续运行。
[ 通过InfoWorld的App Dev Report新闻通讯了解软件开发中的热门话题 ]
在Python中使用较低级别的异步
最后,如果您认为所构建的应用程序可能需要asyncio
的较低级组件,请在开始编码前先看看以下内容:很有可能有人已经构建了一个异步驱动的Python库来满足您的需求。
例如,如果您需要异步DNS查询,请检查aiodns
库,对于异步SSH会话,有asyncSSH
。 通过关键字“ async”(以及其他与任务相关的关键字)搜索PyPI,或查看手工编写的Awesome Asyncio列表以获取想法。
翻译自: https://www.infoworld.com/article/3526429/how-to-use-asyncio-in-python.html