How to parallelise blocking code with asyncio
我知道 StackOverflow 中的 asyncio 功能很多,但尽管这里回答了很多问题,但我仍然不明白如何做一些简单的事情,比如并行化 2 个执行阻塞代码的任务。
例如,这很好用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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() |
输出正是我正在寻找的:
1 2 3 4 5 6 7 | Alpha start Bravo start *2 second wait* Alpha stop Bravo stop Alpha Bravo |
但是,如果我将
1 2 3 4 5 6 7 8 | Alpha start *2 second wait* Alpha stop Bravo start *2 second wait* Bravo stop Alpha Bravo |
问题是,在我的真实示例中,我无法控制那些缓慢的代码,因此我无法将其更改为使用协程。在某些情况下,它只是
所以我想知道 asyncio 是否是正确的工具。当您尝试与 .gather() 并行化时,是否可以在异步代码中使用阻塞代码?
还请注意,我(不幸地)在这方面坚持使用 Python 3.6。我正在编写一个 Mycroft 扩展程序,而这正是他们目前所坚持的环境。
在我在这里以评论的形式获得帮助后,我能够使用
汇总一个解决方案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | import concurrent.futures import time def slow_1(s): time.sleep(5) print(f"1: {s}") return"1: ok" def slow_2(s): time.sleep(1) print(f"2: {s}") return"2: ok" def slow_3(s): time.sleep(1) print(f"3: {s}") return"3: ok" with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor: futures = ( executor.submit(slow_1,"x"), executor.submit(slow_2,"y"), executor.submit(slow_3,"z"), ) concurrent.futures.wait(futures) for future in futures: try: print(future.result()) except: # This should obviously be more explicit pass |
哪些输出:
1 2 3 4 5 6 | 2: y 3: z 1: x 1: ok 2: ok 3: ok |
我应该注意到,官方文档并不清楚你可以通过在未来调用
只有当有东西等待时,协程才能"并行"做一些事情。例如,在您上面的代码中,它与 asyncio.sleep 一起工作的原因是您可以在其上等待它。您只能等待为此目的而设计的特定功能。这就是标准 time.sleep 不起作用的原因,因为您不能使用关键字 await 。 requests 库也是如此。
幸运的是,您可以使用美妙的 aiohttp 库:https://docs.aiohttp.org
这将为您提供同时发出多个请求所需的确切信息。