PySide6.QtAsyncio¶
注意
此模块目前处于技术预览阶段。
Qt Asyncio 模块是一个纯 Python 模块,允许编写使用 Qt 的 API 与 asyncio 结合的程序。asyncio 是一个流行的 Python 库,用于异步编程。它特别适用于需要处理来自多个来源的许多 I/O 操作的程序,例如 Web 服务器。更一般地说,它允许开发者使用 couroutines。 协程可以被想象为“异步函数”。与 Qt 的信号和槽机制相比,这使得异步程序的程序流程更接近于同步程序,因为程序不再需要被想象为一系列回调。相反,协程在指定的位置透明地恢复和让步。
考虑以下使用async
关键字定义在其定义前面的简单协程:
async def do_something():
result = await do_something_asynchronously()
print(result)
do_something_asynchronously()
本身是一个协程,例如,一个通常在同步程序中会阻塞执行流程的I/O密集型操作。相反,使用 await
关键字来等待结果,此时 do_something()
会暂停,程序流程透明地切换到下一个异步任务。当结果可用时,程序流程能够切换回 do_something()
协程,然后恢复并打印结果。
asyncio API¶
asyncio 和 Qt 都基于事件循环。asyncio 提供了一个 API,可以用自定义实现替换其默认的事件循环。QtAsyncio 提供了这样一个实现,它使用 Qt 的事件循环,允许 Qt 和 asyncio 一起使用。
我们认为这个API由两个层次组成:
一个面向用户的API,用于应用程序中,包括传输和协议、网络连接、服务器、套接字、信号、子进程。
QtAsyncio 目前涵盖了第一层。这包括以下函数,这些函数的API与QtAsyncio和asyncio相同:
还包括在
执行器中运行同步代码
(ThreadPoolExecutor
)的能力。
开始使用QtAsyncio¶
要使用QtAsyncio编写程序,首先导入模块,例如:
import PySide6.QtAsyncio as QtAsyncio
QtAsyncio 提供了一个函数 run()
,可以用于运行特定的协程直到其完成,或者简单地启动 Qt 和 asyncio 事件循环。如果程序流程从所述协程开始,前一种情况是有意义的;如果在程序流程的后期(例如,在用户界面中按下按钮后)将协程加入队列,后一种情况是有意义的。
QtAsyncio.run()
(参见asyncio “minimal” 示例 以了解此用法的实例) 或
QtAsyncio.run(my_coroutine())
(参见asyncio “Eratosthenes”示例) 或
QtAsyncio.run(my_coroutine(), keep_running=False)
运行协程并在其完成后停止事件循环。
后一种情况的行为与 asyncio.run(my_coroutine())
完全相同。
如果还没有QCoreApplication、QGuiApplication或QApplication的实例,则会创建一个新的QCoreApplication实例。
可以传递一个额外的可选参数 quit_qapp
给 run()
,以配置当 asyncio 完成时是否应关闭位于 QtAsyncio 核心的 QCoreApplication。一个特殊的情况是,如果希望在所有单元测试中重复使用单个 QCoreApplication 实例,则可能需要禁用此功能,因为如果每次关闭此实例,测试将失败。默认值为 True
。
请注意,这个参数与keep_running
参数是正交的。
keep_running
决定asyncio在协程完成后是否应继续运行,
而quit_qapp
决定在asyncio完成后是否应关闭QCoreApplication。
有可能asyncio完成时,QCoreApplication仍然保持活动状态。
参数 handle_sigint
决定 QtAsyncio 是否应该处理 SIGINT(Ctrl+C)并在接收到时关闭事件循环。默认值为 False
。如果您希望 QtAsyncio 负责处理 SIGINT 而不是您的程序,请将其设置为 True
。
协程解释¶
协程是可以暂停(yield)和恢复的函数。在这个简单的概念背后,隐藏着一个由异步框架抽象的复杂机制。本次演讲展示了下面的图表,试图说明从协程提供给异步框架到其完成的过程。
