2017-04-05 92 views
14

我使用aiohttp來構建一個將TCP請求發送到單獨服務器的API服務器。發送TCP請求的模塊是同步的,並且是我的目的的黑盒子。所以我的問題是這些請求阻止了整個API。我需要一種將模塊請求封裝在異步協程中的方法,該協議不會阻塞其餘的API。如何在異步協程中包裝同步函數?

所以,僅僅用sleep作爲一個簡單的例子,有沒有辦法以某種方式包裹在無阻塞協程耗時同步碼,這樣的事情:

async def sleep_async(delay): 
    # After calling sleep, loop should be released until sleep is done 
    yield sleep(delay) 
    return 'I slept asynchronously' 
+1

你總是在I/O塊。通過合作性多任務處理,您無法獲得所需的行爲,因爲阻止的協同程序僅在請求完成後才返回控制(收益)。 –

+1

aiohttp適用於http。對於非http TCP,asyncio就足夠了。 – Udi

回答

15

最終我找到了答案this thread。我正在尋找的方法是run_in_executor。這允許異步運行同步功能而不阻塞事件循環。

sleep例子我張貼以上,這可能是這樣的:

import asyncio 
from time import sleep 
from concurrent.futures import ProcessPoolExecutor 

async def sleep_async(loop, delay): 
    # Can set executor to None if a default has been set for loop 
    await loop.run_in_executor(ProcessPoolExecutor(), sleep, delay) 
    return 'I slept asynchronously' 

另請參閱下面的答案 - >How do we call a normal function where a coroutine is expected?

+8

'ProcessPoolExecutor'成本高,因爲它啓動了一個全新的python解釋器。當您需要使用多個處理器的CPU密集型任務時使用它。考慮使用'ThreadPoolExecutor',而不是使用線程。 – Oleg

+3

感謝您的額外信息。雖然最初的例子使用了進程池,但是ThreadPoolExecutor是我在經過多一點研究之後最終使用的。看起來還是有些狡猾,但到目前爲止,它們都在一起。 –

+2

請注意,不是創建一個新的執行程序,而是通過調用'loop.run_in_executor(executor = None,func,* args)'來使用默認執行程序可能會更簡單一些(參見[documentation](https:// docs。 python.org/3/library/asyncio-eventloop.html#asyncio.AbstractEventLoop.run_in_executor))。 –