2017-04-05 86 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))。 –

相关问题