如何将 asyncio 与外部事件循环集成?
How can I integrate asyncio with an external event loop?
我正在编写一个事件驱动程序,其中的事件调度是用 C 语言编写的。该程序使用 Python 作为扩展模块。我想让扩展模块使用 async
/await
语法来实现协程。协程只会与我的程序的一部分交互,不涉及 IO。我的 C 调度程序是单线程的,我需要协程在其线程中执行。
在纯Python程序中,我会直接使用asyncio
,让我的程序使用它的事件循环来驱动所有事件。然而,这不是一种选择;我的事件循环需要每秒处理数百万个基于 C 的事件,我负担不起 Python 的开销。
我尝试编写自己的事件循环实现,将所有调度委托给我的 C 调度程序。我尝试了几种方法:
- 重新实现
EventLoop
、Future
、Task
等以模仿 asyncio
的工作方式(减去 IO),以便 call_soon
将调度委托给我的 C 事件循环。这是安全的,但需要一些工作,并且在文档、调试支持、复杂的语义细节和 correctness/test 覆盖率方面,我的实现总是不如 asyncio
。
- 我可以使用
asyncio
中的 vanilla Task
、Future
等,并且只创建 AbstractEventLoop
的自定义实现,将调度委托给我的 C 事件循环同样的方式。这非常简单,但我可以看到 vanilla EventLoop
访问了不明显的内部结构(task._source_traceback
、_asyncgen_finalizer_hook
、_set_running_loop
),所以我的实现仍然是第二个 class。我还必须依靠未记录的 Handle._run
来实际调用回调。
- 如果我从
BaseEventLoop
而不是 AbstractEventLoop
进行子class,事情似乎会变得更简单更好(但文档说我不应该那样做)。不过我还是需要Handle._run
。
- 我可以生成一个单独的线程
run_forever
:s a vanilla asyncio.DefaultEventLoop
和 运行 我所有的协程,但协程取决于我程序的扩展 API,它不支持并发调用。所以我必须以某种方式让 DefaultEventLoop
在调用 Handle._run()
时暂停我的 C 事件循环。我没有找到实现该目标的合理方法。
关于如何最好地做到这一点有什么想法吗?其他人是怎么解决这个问题的?
我发现 trio
, a third-party alternative to asyncio
, provides explicit support for integration with alien event loops through something called guest mode。解决了我的问题!
我正在编写一个事件驱动程序,其中的事件调度是用 C 语言编写的。该程序使用 Python 作为扩展模块。我想让扩展模块使用 async
/await
语法来实现协程。协程只会与我的程序的一部分交互,不涉及 IO。我的 C 调度程序是单线程的,我需要协程在其线程中执行。
在纯Python程序中,我会直接使用asyncio
,让我的程序使用它的事件循环来驱动所有事件。然而,这不是一种选择;我的事件循环需要每秒处理数百万个基于 C 的事件,我负担不起 Python 的开销。
我尝试编写自己的事件循环实现,将所有调度委托给我的 C 调度程序。我尝试了几种方法:
- 重新实现
EventLoop
、Future
、Task
等以模仿asyncio
的工作方式(减去 IO),以便call_soon
将调度委托给我的 C 事件循环。这是安全的,但需要一些工作,并且在文档、调试支持、复杂的语义细节和 correctness/test 覆盖率方面,我的实现总是不如asyncio
。 - 我可以使用
asyncio
中的 vanillaTask
、Future
等,并且只创建AbstractEventLoop
的自定义实现,将调度委托给我的 C 事件循环同样的方式。这非常简单,但我可以看到 vanillaEventLoop
访问了不明显的内部结构(task._source_traceback
、_asyncgen_finalizer_hook
、_set_running_loop
),所以我的实现仍然是第二个 class。我还必须依靠未记录的Handle._run
来实际调用回调。 - 如果我从
BaseEventLoop
而不是AbstractEventLoop
进行子class,事情似乎会变得更简单更好(但文档说我不应该那样做)。不过我还是需要Handle._run
。 - 我可以生成一个单独的线程
run_forever
:s a vanillaasyncio.DefaultEventLoop
和 运行 我所有的协程,但协程取决于我程序的扩展 API,它不支持并发调用。所以我必须以某种方式让DefaultEventLoop
在调用Handle._run()
时暂停我的 C 事件循环。我没有找到实现该目标的合理方法。
关于如何最好地做到这一点有什么想法吗?其他人是怎么解决这个问题的?
我发现 trio
, a third-party alternative to asyncio
, provides explicit support for integration with alien event loops through something called guest mode。解决了我的问题!