2016-11-20 79 views
0

我很新asyncio並需要一些關於如何構建以下方案的建議。我有一個Cython擴展它接受回調。每次新事件到達時前者都會執行。然而,啓動收集這些事件的機制是阻塞操作,即阻塞主線程。 Cython擴展也接受asyncio.Queue,並從回調調用put_nowait方法。現在我想設置隊列的使用者來處理事件。這可能是該方案背後可能的僞代碼:asyncio麻煩和建議

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

在執行了一定數量的字節碼操作後,普通的Python代碼將允許另一個線程輪流。例如,參見this set of slides,其討論機制的改進,但也解釋了機制。

Cython不會執行字節碼,所以永遠不會觸發這個交換機制,所以Cython線程將無限期地阻塞(就像您發現的那樣)。一個簡單的捷徑可走的是以下行添加到您的主用Cython環路cext.start(所以定期執行):

with nogil: 
    pass 

此版本中,然後立即嘗試回收全局解釋器鎖(GIL),它允許要執行的其他線程(如果另一個線程執行,則Cython將不得不等待)。

一個更好的選擇是識別不需要GIL(主要是使用C數據類型的位,而不是Python數據類型)的Cython代碼位並將其包裝在with nogil:塊中。這將允許您的Cython代碼在另一個線程也運行時繼續執行有用的事情。

+0

它不回答我的問題。然而,爲了克服GIL的限制,開始重構代碼已經成爲一種動機。我正在試驗極高的性能提升。 – Nedo

+0

那麼,我很高興它以某種方式幫助,如果不是你想要的方式!恐怕我不太瞭解'asyncio'足夠進一步的幫助(這個答案有點臆測,因爲它有時候會出現在Cython中)。如果您爲'CythonExtension'顯示了一些簡化的示例代碼,它可能會幫助其他人回答這個問題。 – DavidW

+0

另一個想法是:是否執行'c'',找到一個空隊列並在擴展有時間添加任何內容之前完成? (或者我誤解了?) – DavidW