使用Python asyncio接口与Cython库

时间:2017-07-20 12:35:03

标签: python cython python-asyncio

我在C ++中有一个由Cython包装的外部库。这个C ++库本身我无法改变。我想将该库用作Python应用程序的一部分,该应用程序使用asyncio作为其主要进程控制。

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

我的问题是,我怎样才能最好地建模这个与asnycio配合使用的接口,而不是破解临时解决方案来使用Cython库方法?我把它写成asyncio.Protocol和asyncio.Transport然后使用Cython库作为它的底层通信机制。但是,通过一些猴子修补使它看起来像一个插座看起来很费劲。是否有更好的方法或抽象方法可以将包装器放在外部库上以使其与asyncio一起使用?

1 个答案:

答案 0 :(得分:2)

要回答我自己的问题,据我所知,没有义务在asyncio中使用Protocol或Transport提供的抽象来构建应用程序。我找到的最佳建模是使用常规类,其方法定义为async。然后可以使该类看起来像任何符合您要求的模式。如果要包装的代码与套接字的整体用例不同,则这尤其重要。 asyncio提供的抽象本身就是非常准确的。 对于像Cython包装的C ++阻塞代码这样复杂的东西,您需要使用多处理来处理它。这是为了避免挂起翻译。 Asyncio无法在不进行更改的情况下运行阻止代码。必须专门编写代码才能兼容asyncio。

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

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

使用uvloop的Asyncio

count   10001.000000
mean    76435.956504
std      8887.459462
min     63608.000000
25%     71709.000000
50%     74104.000000
75%     79496.000000
max    287204.000000

标准Asyncio事件循环

count   10001.000000
mean   199741.937506
std     27900.377114
min    173321.000000
25%    185545.000000
50%    191839.000000
75%    205279.000000
max    529246.000000