【发布时间】:2020-06-09 03:33:19
【问题描述】:
我知道 StackOverflow 中的 asyncio 功能很多,但尽管这里回答了很多问题,但我仍然不明白如何做一些简单的事情,比如并行化 2 个执行阻塞代码的任务。
例如,这很好用:
import asyncio
async def slow_thing():
await asyncio.sleep(2)
async def try_alpha():
print("Alpha start")
await slow_thing()
print("Alpha stop")
return "Alpha"
async def try_bravo():
print("Bravo start")
await slow_thing()
print("Bravo stop")
return "Bravo"
async def main():
futures = [
try_alpha(),
try_bravo(),
]
for response in await asyncio.gather(*futures):
print(response)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
输出正是我想要的:
Alpha start
Bravo start
*2 second wait*
Alpha stop
Bravo stop
Alpha
Bravo
但是,如果我将await syncio.sleep(2) 换成time.sleep(2),输出就好像我的代码没有任何异步:
Alpha start
*2 second wait*
Alpha stop
Bravo start
*2 second wait*
Bravo stop
Alpha
Bravo
问题是,在我的真实示例中,我无法控制那些慢代码,因此我无法将其更改为使用协程。在某些情况下,这只是 requests.get() 的一堆用途,而在其他情况下,我正在使用 kodijson 库,它做了很多我无法访问的事情。
所以我想知道 asyncio 是否是正确的工具。当您尝试与 .gather() 并行时,是否可以在异步代码中使用阻塞代码?
另外请注意,我(不幸地)在这方面坚持使用 Python 3.6。我正在写一个Mycroft 扩展,这就是他们目前所坚持的环境。
【问题讨论】:
-
对于阻塞呼叫,使用
loop.run_in_executor -
另外请注意,如果您没有一堆代码可以在
asyncio之上利用异步 I/O,那么它可能不是您的应用程序的正确选择,并且你应该直接使用threading/multiprocessing/concurrent.futures。 -
我用
loop.run_in_executor(None, time.sleep, 2)替换了sleep行,它有点 有效。它在应该等待的地方等待,但也会打印出错误:RuntimeError: Event loop is closed -
但是您使用
concurrent.futures的建议看起来可能对我有用,谢谢! -
This answer 展示了如何将
concurrent.futures直接用于此类任务。
标签: python python-asyncio