Using Python asyncio interfaces with Cython libraries
我有一个C++的外部库,它已经被Cython包住了。这个C++库本身无法更改。我想结合这个库,将其作为使用Asyncio作为其主要进程控制的Python应用程序的一部分使用。
Cython库基本上用一个专有的协议来进行网络工作。但是,当库的事件处理程序在python中启动时,cython库正在阻塞。我已经把它带到了一个阶段,我可以通过Python函数接收从C++库接收到的事件的回调。如果我在"执行器"中的event_loop.run_内运行事件处理程序,我可以解决在库事件处理程序处挂起应用程序的库。
我的问题是,我如何才能最好地对它进行建模,使其能够与ASNYCIO配合使用,而不是对使用Cython库方法的临时解决方案进行黑客攻击?我曾经研究过将其作为asyncio.protocol和asyncio.transport编写,然后使用cython库作为底层通信机制。不过,看起来要想让它看起来像一个插座,需要花费很多精力来修补猴子。是否有更好的方法或抽象方法将包装器放在外部库上,使其与Asyncio一起工作?
为了回答我自己的问题,就我所见,没有义务使用协议或异步传输提供的抽象来构造应用程序。对于这个问题,我发现最好的建模方法是使用一个定义为Async的常规类。然后可以使类看起来像符合您要求的任何模式。如果要包装的代码与套接字的总体使用情形不同,那么这一点尤其重要。异步提供的抽象本身是非常简单的。对于复杂的东西,比如Cython包的C++阻塞代码,你需要用多重处理来处理它。这是为了避免挂译员。Asyncio不能在不进行更改的情况下运行阻塞代码。必须专门编写与异步兼容的代码。
我所做的是将整个阻塞代码(包括对象的构造)放入一个函数中,该函数是在执行器中使用event_loop.run_执行的。除此之外,我还使用了一个Unix套接字来与进程通信,以获取命令和回调数据。由于使用了Unix套接字,您可以在主应用程序中使用asnycio方法,管道也是如此。
下面是我从多进程进程生成器向Asyncio主进程发送128个字节得到的一些结果。数据以10毫秒的间隔生成。使用time.perf_counter()对持续时间进行了计时。下面的结果以纳秒为单位。这台机器本身就是运行Linux内核4.10.17的Intel(R)Core(tm)i7-2600 [email protected]。
带uvloop的异步
1 2 3 4 5 6 7 8 | count 10001.000000 mean 76435.956504 std 8887.459462 min 63608.000000 25% 71709.000000 50% 74104.000000 75% 79496.000000 max 287204.000000 |
标准异步事件循环
1 2 3 4 5 6 7 8 | count 10001.000000 mean 199741.937506 std 27900.377114 min 173321.000000 25% 185545.000000 50% 191839.000000 75% 205279.000000 max 529246.000000 |