aiofiles 是最稳妥的异步文件写入方案,因 aiofile 在并发下存在文件偏移竞争致内容撕裂、换行错位等问题;正确做法是用 aiofiles.open(..., "a") 配合全局 asyncio.lock 包裹全部相关写入操作,确保逻辑原子性。

aiofiles 是目前最稳妥的异步文件写入方案,aiofile 在并发场景下不可靠,容易因文件偏移竞争导致内容撕裂、换行错位、行首截断。
为什么 aiofile 会丢数据?
它的 write() 不是原子操作,底层对文件指针(offset)的管理在多协程间不一致;即使加了 asyncio.Lock,若锁粒度太细(比如只锁单次 write()),两个协程仍可能交替跳转到同一偏移位置覆盖写入。典型现象是:question_output.txt 和 answer_output.txt 中 Q/A 行不再严格对应,甚至出现 "\n第5页,第9条第11页" 这类乱码拼接。
aiofiles + 全局 asyncio.Lock 的正确用法
关键不是“给每个文件单独加锁”,而是让所有相关写入动作被同一把锁包裹,构成逻辑原子单元:
- 用
aiofiles.open(..., "a")替代AIOFile,它行为与同步open()一致,偏移控制可预测 - 锁必须覆盖全部写入语句——比如同时往
q_file和a_file写一行,不能分开加锁 - 避免手动调用
fsync():默认 "a" 模式下await f.write()已触发缓冲,close()自动 flush;强一致性需求才额外加os.fsync() - 示例片段:
async with file_lock: # ← 锁在此处开始
await q_file.write(q + "\n")
await a_file.write(a + "\n") # ← 锁在此处结束,中间无 yield
逐行写 vs 批量写:性能与安全的权衡
逐行 await f.write() 安全但慢;批量写快但需注意内存和换行一致性:
- 若用
"\n".join(lines)一次性写入,必须确保每条记录本身不含\n,否则 CSV/JSON 格式会崩 - 对大结果集,建议分 batch(如每 100 条一组),既减少系统调用,又避免单次写入过长阻塞事件循环
- 不要在批量写前自己做
str.encode()——aiofiles会按 open 时指定的 encoding 处理,手动编码易引发UnicodeEncodeError
容易被忽略的细节
异步写入的安全边界不在语法,而在**锁的作用范围**和**文件打开模式**。很多人以为加了 Lock 就万事大吉,却忘了锁没包住 flush() 或跨文件写入顺序;也有人用 "w" 模式反复打开同一个文件,导致前面写的内容被清空。真正起作用的,永远是那几行被锁住的实际 I/O 调用,而不是锁对象本身。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











