aiofiles.open写文件更慢是因为默认无缓冲,每次write都触发系统调用,且底层依赖线程池而非真正的异步I/O;提升吞吐关键在减少I/O次数、合理限流并发,并根据场景选择同步buffering或asyncio.to_thread。

为什么直接用 aiofiles.open 写文件反而更慢?
因为 aiofiles.open 默认不缓冲,每次 write() 都触发一次系统调用(即使内容很小),在高并发场景下会放大事件循环调度开销。真正提升吞吐的关键不是“用异步函数”,而是减少 I/O 次数 + 合理控制协程并发量。
- 单个大文件写入:用同步
open()+buffering=8192通常比aiofiles更快 - 大量小文件并发写入:才适合
aiofiles,但必须配合asyncio.Semaphore限流,否则可能耗尽系统文件描述符或触发OSError: Too many open files -
aiofiles底层仍依赖线程池(loop.run_in_executor)模拟异步,不是真正的异步 I/O —— 这点常被忽略
如何安全地并发写入多个文件?
核心是用 asyncio.Semaphore 控制同时打开的文件数,避免资源打满。示例中限制为 10 个并发写操作:
import asyncio import aiofiles import ossem = asyncio.Semaphore(10) # 控制最大并发写入数
async def write_file(filename: str, content: str): async with sem: # 等待许可 try: async with aiofiles.open(filename, "w") as f: await f.write(content) except OSError as e: if e.errno == 24: # Too many open files print(f"警告:{filename} 写入失败 - {e}") raise
启动 100 个写任务
tasks = [writefile(f"out{i}.txt", f"data_{i}") for i in range(100)] await asyncio.gather(*tasks, return_exceptions=True)
- 不要省略
async with sem,尤其在循环中启动大量任务时 -
return_exceptions=True防止一个失败导致整个gather中断 - 注意
aiofiles.open(..., "w")不支持buffering参数,无法像同步那样调优缓冲区
写入大字符串时要不要手动分块?
要。如果单次 write() 传入几 MB 的字符串,aiofiles 会把它整个加载进内存再交由线程池处理,容易引发内存峰值。建议按 64KB~1MB 分块写入:
立即学习“Python免费学习笔记(深入)”;
async def write_large_content(filename: str, content: str, chunk_size: int = 1024*64):
async with aiofiles.open(filename, "w") as f:
for i in range(0, len(content), chunk_size):
chunk = content[i:i + chunk_size]
await f.write(chunk)
- 分块大小不是越大越好:超过 1MB 可能增加单次线程池阻塞时间
- 若内容来自生成器(如逐行处理日志),优先用
async for line in ...流式写入,而非拼成大字符串 - 对超大文件(>1GB),考虑用同步方式配合
mmap或shutil.copyfileobj,异步在此场景无优势
有没有比 aiofiles 更适合高并发写的替代方案?
有,但取决于场景。纯文本批量写入时,asyncio.to_thread + 同步 open 往往更稳、更易调试:
import asyncioasync def sync_write_in_thread(filename: str, content: str): def _write(): with open(filename, "w", buffering=8192) as f: f.write(content) await asyncio.to_thread(_write)
-
to_thread(Python 3.9+)比aiofiles更轻量,且能利用buffering和newline等底层优化 - 如果项目已用
aiofiles,不必强行替换;但新项目遇到写性能瓶颈,先测to_thread版本 - 真正需要异步 I/O 的场景(如网络响应直接落盘、实时日志流),应考虑
uvloop+libuv绑定方案,而非纯 Python 层的aiofiles
实际压测中,多数 Web 日志或批处理写入场景,瓶颈不在「是否异步」,而在磁盘随机写延迟和 OS 文件缓存策略。别过早优化 aiofiles 调用本身,先确认是不是真的卡在写文件上。










