将 Python asyncio 接口与 Cython 库结合使用

0x0*_*x00 3 python cython python-asyncio

我有一个由 Cython 封装的 C++ 外部库。这个 C++ 库本身我无法更改。我想将该库组合起来用作Python应用程序的一部分,该应用程序使用asyncio作为其主要过程控制。

Cython 库本质上是使用专有协议进行网络工作。然而,当在 python 中启动库的事件处理程序时,Cython 库会阻塞。我已经达到了可以传递 Python 函数并接收从 C++ 库接收的事件的回调的阶段。如果我在 event_loop.run_in_executor 中运行事件处理程序,我可以解决库在库事件处理程序中挂起应用程序的问题。

我的问题是,我如何才能最好地对此进行建模,以便与与其接口完美契合的 asnycio 一起使用,而不是破解临时解决方案以使用 Cython 库方法?我考虑将其编写为 asyncio.Protocol 和 asyncio.Transport,然后使用 Cython 库作为其底层通信机制。然而,看起来需要付出很大的努力才能使它看起来像一个套接字。是否有更好的方法或抽象来将包装器放在外部库上以使其与 asyncio 一起使用?

0x0*_*x00 5

为了回答我自己的问题,据我所知,没有义务使用 asyncio 中的协议或传输提供的抽象来构建应用程序。我发现对此的最佳建模是使用常规类,其方法定义为异步。然后可以使该类看起来像任何适合您要求的模式。如果您正在包装的代码不具有与套接字相同的整体用例,则这一点尤其重要。asyncio 提供的抽象本身非常准系统。\n对于像 Cython 包装的 C++ 阻塞代码这样复杂的事情,您需要使用多处理来处理它。这是为了避免挂起翻译器。Asyncio 无法在不进行更改的情况下运行阻塞代码。必须专门编写代码才能兼容 asyncio。

\n\n

我所做的是将整个阻塞代码(包括对象的构造)放入一个由 event_loop.run_in_executor 执行的函数中。除此之外,我还使用 unix 套接字与进程通信以获取命令和回调数据。由于使用 unix 套接字,您可以在主应用程序中使用 asnycio 方法,管道也是如此。

\n\n

以下是我从多进程进程生产者发送 128 字节到 asyncio 主进程得到的一些结果。数据以 10 毫秒的间隔生成。持续时间使用 time.perf_counter() 进行计时。下面的结果以纳秒为单位。该机器本身是 Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz,运行 Linux 内核 4.10.17。

\n\n

带有 uvloop 的异步

\n\n
\n计数 10001.000000\n平均值 76435.956504\nstd 8887.459462\n最小值 63608.000000\n25% 71709.000000\n50% 74104.000000\n75% 79496.000000\n最大值 28 7204.000000\n
\n\n

标准异步事件循环

\n\n
\n计数 10001.000000\n平均值 199741.937506\nstd 27900.377114\n最小值 173321.000000\n25% 185545.000000\n50% 191839.000000\n75% 205279.000000 \n最大 529246.000000\n
\n