【.com速译】Python的异步编程特性(简称async)可以让你编写出做更多工作的程序,而无需等待独立的任务完成。Python附带的asyncio库为您提供了处理磁盘或网络I/O异步的工具,而无需在另一端等待。asyncio提供了两个用于处理异步操作的API:高级和低级。高级API用途广泛,适用于各种应用程序。低级API功能强大,但也很复杂且使用频率较低。本文重点介绍高级API。我们将介绍asyncio中常用的高级API,展示它们如何用于涉及异步任务的常见操作。如果您对Python中的异步完全陌生,或者想了解它是如何工作的,您不妨先阅读我关于Python异步的文章:https://www.infoworld.com/article/3454442/get-started-with-async-in-python.html,稍后再深入挖掘。在Python中运行协程和任务很自然,asyncio最常见的用途是运行Python脚本的异步部分。这意味着学习使用协程和任务。Python的异步组件(包括coroutines和tasks)只能和其他异步组件一起使用,不能和常规的同步Python一起使用,所以需要asyncio来填补这个空缺。为此,您使用asyncio.run函数:importasyncioasyncdefmain():print("Waiting5seconds.")for_inrange(5):awaitasyncio.sleep(1)print(".")print("Finishedwaiting.")asyncio.run(main())这将运行main()以及由main()触发的任何例程,等待结果返回。一般来说,一个Python程序应该只有一个.run()语句,就像一个Python程序应该只有一个main()函数一样。如果不小心使用,async会使程序的控制流难以阅读。程序的异步代码只有一个入口点可以避免复杂化。异步函数也可以安排到任务中,对象是包装协程并帮助运行它们的对象。然后在事件循环中运行asyncdefmy_task():do_something()task=asyncio.create_task(my_task())my_task()并将结果存储在任务中。如果你只有一个任务并且想得到结果,你可以使用asyncio.wait_for(task)等待任务完成,然后使用task.result()检索结果。但是,如果您有许多计划要执行的任务并希望等待所有任务完成,您不妨使用asyncio.wait([task1,task2])来收集结果。(请注意,如果您不希望操作在特定时间长度后运行,则可以设置超时。)在Python中管理异步事件循环asyncio的另一个常见用途是管理异步事件循环。事件循环是运行异步函数和回调的对象。它是在使用asyncio.run()时自动创建的。您通常希望每个程序只使用一个异步事件循环,同样是为了便于管理。如果您正在编写服务器等更高级别的软件,则需要对事件循环进行较低级别的访问。为此,您可以“窥视面纱”并直接访问事件循环的内部结构。但如果这是一项简单的工作,则无需执行此操作。在Python中使用流异步读取和写入数据的最佳用例是长时间运行的网络操作,其中应用程序可能会阻塞等待其他资源返回结果。为此,asyncio提供了流,一种用于执行网络I/O的高级机制。这包括充当Web请求的服务器。asyncio使用两个类,StreamReader和StreamWriter,在网络上进行高级读写。如果要从网络读取,可以使用asyncio.open_connection()打开连接。此函数返回StreamReader对象和StreamWriter对象的元组,您可以在每个对象上使用.read()和.write()方法进行通信。要接受来自远程主机的连接,请使用asyncio.start_server()。asyncio.start_server()函数接受回调函数client_connected_cb作为参数,只要收到请求就会调用该函数。回调函数将StreamReader和StreamWriter的实例作为参数,以便您可以处理服务器的读/写逻辑。此示例(https://gist.github.com/ethanfrey/75e58db27095936b9e5e)介绍了一个使用异步驱动的aiohttp库的简单HTTP服务器。Python中的同步任务异步任务通常独立运行,但有时您希望它们相互通信。asyncio提供队列和其他几种任务间同步机制:队列:asyncio队列允许异步函数将Python对象排队以供其他异步函数使用——例如,根据行为负载在不同类型的函数之间分配工作。同步原语:asyncio中的锁、事件、条件和信号与常规Python锁、事件、条件和信号一样工作。关于所有这些方法要记住的一件事是它们不是线程安全的。对于在同一事件循环中运行的异步任务来说,这不是问题。但是,如果您尝试与不同事件循环、操作系统线程或进程中的任务共享信息,则需要使用线程模块及其对象来实现。此外,如果您想跨线程边界启动协程,请使用asyncio.run_coroutine_threadsafe()函数并将事件循环作为参数传递给它。Python中另一个常见但很少讨论的asyncio用法是在协程中等待任意时间。为此你不能使用time.sleep(),否则整个程序将被阻塞。相反,应该使用asyncio.sleep(),它允许其他协程继续运行。在Python中使用较低级别的异步最后,如果您认为您正在构建的应用程序可能需要asyncio的较低级别组件,请在开始编程之前考虑一下:很可能有人已经构建了基于异步的Python库。例如,如果您需要异步DNS查找,请查看aiodns库;对于异步SSH会话,有asyncSSH。通过关键字“async”(以及其他与任务相关的关键字)搜索PyPI,或查看AwesomeAsyncio的手工精选列表(https://github.com/timofurrer/awesome-asyncio)以获取灵感。原标题:HowtouseasyncioinPython,作者:SerdarYegulalp
