asyncio麻烦&建议

时间:2016-11-20 19:49:45

标签: python asynchronous cython python-asyncio

我是 asyncio 的新手,需要一些有关如何构建以下方案的建议。我有一个 Cython 扩展,它接受一个回调。每次新事件到来时都会执行前者。然而,启动收集那些事件的机制是阻塞操作,即它阻塞主线程。 Cython扩展还接受asyncio.Queue,并从回调中调用put_nowait方法。现在我想设置队列的使用者来处理事件。这可能是场景背后可能的伪代码:

aioq = asyncio.Queue(1000)    
cext = CythonExtension(aioq)

def c(aioq):
   while not aioq.empty():
      e = yield from aioq.get()
loop.create_task(c(aioq))

# i'm not sure how to run the event loop
# and keep on initializing the cython extension
# because this call also blocks...
#loop.run_forever()   

# so i tried this.

loop.run_in_executor(None, cext.start) <- this is a blocking operation
# start the event loop
loop.run_forever()

当我运行示例时,asyncio队列充满了事件,但c任务从未执行 - 我无法从队列中获取任何事件。非常感谢有关如何解决此问题的任何反馈或指示。

1 个答案:

答案 0 :(得分:1)

常规Python代码将在执行一定数量的字节码操作后允许另一个线程转动。例如,请参阅this set of slides,其中讨论了该机制的改进,但也解释了该机制。

Cython不会执行字节码,因此永远不会触发此交换机制,因此Cython线程将无限期地阻塞(正如您所发现的那样)。绕过它的一个简单方法是将以下行添加到 The string is ��_o�Remove2 The string is ��_o�Remove23 The string is ��_o�Remove232 The string is ��_o�Remove232 中的主Cython循环中(因此它会定期执行):

cext.start

这个版本,然后立即尝试回收全局解释器锁(GIL),它允许其他线程执行(如果另一个线程执行,那么Cython将不得不等待)。

更好的选择是识别不需要GIL的Cython代码位(主要是使用C数据类型的位,而不是Python数据类型)并将它们包装在with nogil: pass 块中。这将允许你的Cython代码继续做一些有用的东西,而另一个线程也运行。