如何使用asyncio异步调用无返回值的耗时IO/绘图函数?
嘿,这就帮你把调用异步函数的事儿理清楚~
首先,你的doStuff函数已经用async def定义成异步函数了,但调用异步函数得依托asyncio的事件循环,不同Python版本的写法略有区别,我给你分情况说明:
1. Python 3.7+ 推荐写法:用asyncio.run()
这是Python 3.7之后官方推荐的最简方式,它会帮你自动创建、运行、关闭事件循环,不用手动处理那些繁琐的循环操作:
import asyncio import matplotlib.pyplot as plt async def doStuff(input_data): plt.figure() plt.plot(input_data) plt.savefig('foobar.pdf') plt.close() # 记得关闭图形,避免内存占用过高 if __name__ == "__main__": # 示例输入数据 test_input = [1, 3, 2, 5, 4] # 直接用asyncio.run调用异步函数 asyncio.run(doStuff(test_input))
2. 旧版本Python(3.6及以下):手动管理事件循环
如果你的Python版本比较老,就得手动获取事件循环,然后让它运行到任务完成:
import asyncio import matplotlib.pyplot as plt async def doStuff(input_data): plt.figure() plt.plot(input_data) plt.savefig('foobar.pdf') plt.close() if __name__ == "__main__": test_input = [1, 3, 2, 5, 4] # 获取事件循环 loop = asyncio.get_event_loop() # 让循环运行直到doStuff完成 loop.run_until_complete(doStuff(test_input)) # 最后关闭循环 loop.close()
重要补充:关于“真异步”的小提醒
这里得给你提个醒:你写的doStuff里的matplotlib绘图、保存操作其实都是同步阻塞的,单纯用async def包装它并不会让它真的异步执行(也就是说,如果同时调用多个这类函数,它们还是会串行运行)。
如果想让这类阻塞型的IO/绘图操作真正异步并行,你需要把这些同步任务放到线程池或者进程池里运行,比如用Python 3.9+的asyncio.to_thread(),或者旧版本的loop.run_in_executor():
import asyncio import matplotlib.pyplot as plt from concurrent.futures import ThreadPoolExecutor # 先把同步操作单独写成一个普通函数 def sync_draw_and_save(input_data): plt.figure() plt.plot(input_data) plt.savefig(f'foobar_{input_data[0]}.pdf') # 加个后缀区分不同文件 plt.close() # 异步函数里调用线程池执行同步任务 async def async_doStuff(input_data): await asyncio.to_thread(sync_draw_and_save, input_data) # 要是用Python 3.8及以下,就换成下面的写法: # loop = asyncio.get_running_loop() # await loop.run_in_executor(ThreadPoolExecutor(), sync_draw_and_save, input_data) # 如果要同时运行多个任务,用asyncio.gather() async def main(): # 准备多组输入,同时生成多个文件 tasks = [ async_doStuff([1,2,3]), async_doStuff([4,5,6]), async_doStuff([7,8,9]) ] await asyncio.gather(*tasks) if __name__ == "__main__": asyncio.run(main())
这样就能真正实现多个绘图/保存任务的异步并行啦~
内容的提问来源于stack exchange,提问作者FooBar
相关产品推荐
相关产品推荐

