如何将 asyncio 与外部事件循环集成?

问题描述 投票:0回答:2

我正在编写一个事件驱动程序,事件调度是用C语言编写的。该程序使用Python作为扩展模块。我希望允许扩展模块使用

async
/
await
语法来实现协程。协程只会与我的程序的部分交互,不涉及 IO。我的 C 调度程序是单线程的,我需要协程在其线程中执行。

在纯Python程序中,我会按原样使用

asyncio
,并让我的程序使用其事件循环来驱动所有事件。但这不是一个选择;我的事件循环需要每秒处理数百万个基于 C 的事件,但我无法承担 Python 的开销。

我尝试编写自己的事件循环实现,将所有调度委托给我的 C 调度程序。我尝试了几种方法:

  • 重新实现
    EventLoop
    Future
    Task
    等以模仿
    asyncio
    的工作原理(减去 IO),以便
    call_soon
    将调度委托给我的 C 事件循环。这是安全的,但需要一些工作,而且在文档、调试支持、复杂的语义细节和正确性/测试覆盖率方面,我的实现总是不如
    asyncio
  • 我可以使用
    Task
    中的普通
    Future
    asyncio
    等,并且仅创建
    AbstractEventLoop
    的自定义实现,以相同的方式将调度委托给我的 C 事件循环。这非常简单,但我可以看到普通的
    EventLoop
    访问不明显的内部结构(
    task._source_traceback
    _asyncgen_finalizer_hook
    _set_running_loop
    ),所以我的实现仍然是二流的。我还必须依赖未记录的
    Handle._run
    来实际调用回调。
  • 如果我从
    BaseEventLoop
    而不是
    AbstractEventLoop
    进行子类化,事情似乎会变得更简单更好(但文档说我不应该这样做)。不过,我仍然需要
    Handle._run
  • 我可以生成一个单独的线程,
    run_forever
    :一个普通的
    asyncio.DefaultEventLoop
    ,并在那里运行我的所有协程,但协程依赖于我的程序的扩展 API,它不支持并发调用。所以我必须以某种方式让
    DefaultEventLoop
    在调用
    Handle._run()
    时暂停我的 C 事件循环。我没有找到实现这一目标的合理方法。

关于如何最好地做到这一点有什么想法吗?其他人是如何解决这个问题的?

python-3.x python-asyncio
2个回答
0
投票

我发现

trio
asyncio
的第三方替代品,通过称为“访客模式”的东西提供了与外来事件循环集成的明确支持。解决了我的问题!


0
投票
aioguest

,它允许 asyncio 从另一个事件循环运行。 (它的灵感来自 Trio 的访客模式。)

在访客模式下,低级 I/O 等待发生在工作线程上,但线程对用户代码不可见,并且两个事件循环可以相互交互,无需任何特殊同步。

© www.soinside.com 2019 - 2024. All rights reserved.