如何使用asyncio并发执行普通函数任务(非线程方式)
解决asyncio中阻塞函数的并发执行问题
问题根源
你当前代码里的requests.get是同步阻塞IO操作,它会霸占asyncio的事件循环线程,导致其他异步任务(比如wait_task)完全无法被调度执行,直到这个阻塞操作结束,最终两个任务变成了串行运行,和你预期的并发效果不符。
可行解决方案
方法1:用asyncio.to_thread包装阻塞函数(Python 3.9+)
asyncio.to_thread可以把同步阻塞函数放到线程池中执行,这样不会占用事件循环线程,让其他异步任务能正常并发运行。
修改后的完整代码:
import asyncio from time import time import requests async def real_task(): try: print(f"{int(time())} : enter to real task") # 用to_thread包装阻塞的requests.get await asyncio.to_thread( requests.get, "http://10.65.10.183", timeout=5 ) print(f"{int(time())} exit from real task") except Exception as e: print(f"{int(time())} exit from real task") async def wait_task(): print(f"{int(time())} enter into wait task") await asyncio.sleep(3) print(f"{int(time())} exit from wait task") def test(): loop = asyncio.get_event_loop() task_set = set() task_set.add(loop.create_task(real_task())) task_set.add(loop.create_task(wait_task())) loop.run_until_complete( asyncio.wait(task_set) ) test()
执行后就能得到你预期的并发输出:
1723399962 : enter to real task 1723399962 enter into wait task 1723399965 exit from wait task 1723399967 exit from real task
方法2:用loop.run_in_executor(兼容Python 3.9以下)
如果你的Python版本低于3.9,可以用事件循环的run_in_executor方法,手动将阻塞函数放到线程池执行:
async def real_task(): try: print(f"{int(time())} : enter to real task") loop = asyncio.get_running_loop() # 用默认线程池执行阻塞函数 await loop.run_in_executor( None, requests.get, "http://10.65.10.183", timeout=5 ) print(f"{int(time())} exit from real task") except Exception as e: print(f"{int(time())} exit from real task")
核心说明
- asyncio的并发依赖非阻塞IO,所有同步阻塞操作都需要通过线程池或异步专用库来处理,避免卡住事件循环。
- 不管你的实际任务是HTTP请求还是其他同步阻塞函数,都可以用上述两种方法包装,实现真正的asyncio并发。
内容的提问来源于stack exchange,提问作者jiasheng
相关产品推荐
相关产品推荐

