为何I/O绑定场景下AsyncIO性能不及多线程?文件写入测试异常
我分别用AsyncIO和多线程实现了创建8000个文本文件、每个写入100字节数据的功能。由于所有任务都是I/O绑定类型,我原本预期AsyncIO版本会比多线程更快完成,但实际结果却相反:AsyncIO不仅运行速度更慢,内存占用也比多线程版本更高。排查代码后没发现问题,现将两段代码及运行结果附上:
AsyncIO 版本代码
import time import aiofiles import asyncio from timeit import timeit DATA = "A" * 100 async def write_file(filename_plus_path): async with aiofiles.open(filename_plus_path, "w") as f: await f.write(DATA) async def main(): coro = [asyncio.create_task(write_file(f"./file/text{i}.txt")) for i in range(8000)] await coro[-1] st = time.time() print("Started at:", time.strftime("%X")) asyncio.run(main()) print("Finished at:", time.strftime("%X")) res = time.time() - st final_res = res * 1000 print('Execution time:', final_res, 'milliseconds')
AsyncIO 版本输出
Started at: 16:15:39 Finished at: 16:15:44 Execution time: 4243.027448654175 milliseconds
多线程版本代码
import time import threading DATA = "A" * 100 def write_file(filename_plus_path): with open(filename_plus_path, "w") as f: f.write(DATA) print("Started at:", time.strftime("%X")) st = time.time() thrs = [threading.Thread(target=write_file, args=(f"./file/text{i}.txt",)) for i in range(8000)] for th in thrs: th.start() for th in thrs: th.join() res = time.time() - st final_res = res * 1000 print('Execution time:', final_res, 'milliseconds') print("Finished at:", time.strftime("%X"))
多线程版本输出
Started at: 16:16:57 Execution time: 3494.1318035125732 milliseconds Finished at: 16:17:01
问题原因分析
aiofiles 的底层限制:Python 标准库没有提供真正异步的文件I/O API,
aiofiles本质是用线程池包装了同步文件操作。这意味着异步版本不仅没摆脱线程开销,还多了一层AsyncIO调度的额外成本。调度开销差异:AsyncIO依赖单线程事件循环调度所有任务,当任务数量达到8000个时,事件循环的调度开销会被放大。而多线程由操作系统内核直接调度,在大量小I/O任务场景下,内核调度的效率反而更高。
AsyncIO 代码写法不规范:你的AsyncIO代码仅
await coro[-1],只等待最后一个任务完成,没有显式等待全部8000个任务执行完毕。虽然测试中任务可能都完成了,但这种写法存在风险(比如事件循环关闭时部分任务被取消),正确写法应该用await asyncio.gather(*coro)等待所有任务:
import time import aiofiles import asyncio DATA = "A" * 100 async def write_file(filename_plus_path): async with aiofiles.open(filename_plus_path, "w") as f: await f.write(DATA) async def main(): coros = [write_file(f"./file/text{i}.txt") for i in range(8000)] await asyncio.gather(*coros) # 等待所有任务完成 st = time.time() print("Started at:", time.strftime("%X")) asyncio.run(main()) print("Finished at:", time.strftime("%X")) res = time.time() - st final_res = res * 1000 print('Execution time:', final_res, 'milliseconds')
不过即使修正后,由于aiofiles的线程池包装机制,AsyncIO版本的性能依然很难超过多线程——毕竟多线程直接使用操作系统线程,没有额外的异步调度层开销。
总结
在Python中,并非所有I/O绑定任务都适合用AsyncIO。对于文件I/O这类没有原生异步支持的场景,多线程反而可能因为更少的调度开销表现更好。AsyncIO更适合网络I/O(如HTTP请求、Socket通信)这类有原生异步API支持的场景。
内容的提问来源于stack exchange,提问作者novice

