asyncio异步读写文档

237 阅读2分钟

asyncio异步读写文档

在 asyncio 中保存文件时,如果涉及 阻塞式 I/O 操作(例如写入大文件或频繁读写),可以通过以下两种方式。

使用run_in_executor + 线程池

将同步的阻塞文件操作委托给线程池执行,保持异步事件循环的响应性。

代码示例:

import asyncio
from concurrent.futures import ThreadPoolExecutor
from functools import partial

# 全局线程池(避免重复创建)
_executor = ThreadPoolExecutor(max_workers=4)

async def async_save_file(data: str, filename: str) -> None:
    loop = asyncio.get_running_loop()
    
    func = partial(save_file_sync)
    
    # 将同步写入操作提交到线程池
    await loop.run_in_executor(
        _executor, 
        func,  # 同步函数
        *(data, filename)
    )

def save_file_sync(data: str, filename: str) -> None:
    """同步保存文件"""
    with open(filename, "w", encoding="utf-8") as f:
        f.write(data)
    print(f"文件 {filename} 保存成功")

# 使用示例
async def main():
    await async_save_file("Hello, asyncio!", "test.txt")

asyncio.run(main())

使用异步文件库 aiofiles

通过 aiofiles 库实现异步文件操作(底层基于线程池,但语法更符合异步习惯)。

安装依赖

pip install aiofiles

代码示例:

import asyncio
import aiofiles

async def async_save_file(data: str, filename: str) -> None:
    async with aiofiles.open(filename, "w", encoding="utf-8") as f:
        await f.write(data)
    print(f"文件 {filename} 保存成功")

# 使用示例
async def main():
    await async_save_file("Hello, aiofiles!", "test_async.txt")

asyncio.run(main())

备注

两种方式都可以实现异步文件读写操作,这里只给了异步写的示例代码,同理,异步读文件也可以使用类似的方式实现。

相对来说,使用aiofiles,因为封装了接口,所以代码更简洁,更符合异步编程的习惯,两者性能上没有太大的区别,所以如何选择仁者见仁智者见智。

需要特别注意的是不要在异步函数中直接调用同步文件操作(如 open()、f.write()),否则会阻塞事件循环。也要记得使用with 语句或 async with 确保文件句柄正确关闭。