Как выполнять асинхронные файловые операции в Python с использованием asyncio

Ответ

Стандартные файловые операции в Python (open, read, write) являются блокирующими. Их прямой вызов в asyncio коде заморозит весь цикл событий (event loop), сводя на нет преимущества асинхронности.

Для корректной асинхронной работы с файлами существуют два основных подхода:

1. Использование библиотеки aiofiles

Это рекомендуемый и идиоматичный способ. Библиотека предоставляет асинхронный API, который полностью совместим с синтаксисом async/await и не блокирует event loop.

Пример:

import asyncio
import aiofiles

async def main():
    async with aiofiles.open('example.txt', mode='w') as f:
        await f.write('Hello, aiofiles!')

    async with aiofiles.open('example.txt', mode='r') as f:
        content = await f.read()
        print(content)

asyncio.run(main())

2. Использование loop.run_in_executor

Этот метод позволяет выполнить любую блокирующую (синхронную) функцию в отдельном потоке из пула потоков, не блокируя основной цикл событий. Это универсальный способ для интеграции любого синхронного кода в асинхронный.

Пример:

import asyncio

async def read_file_in_executor():
    loop = asyncio.get_running_loop()

    # Открываем файл синхронно
    with open('example.txt', 'r') as f:
        # Выполняем блокирующую операцию f.read() в пуле потоков
        content = await loop.run_in_executor(None, f.read)
        print(content)

# Для записи файла нужно обернуть в функцию
def write_sync(content):
    with open('example.txt', 'w') as f:
        f.write(content)

async def main():
    loop = asyncio.get_running_loop()
    await loop.run_in_executor(None, write_sync, 'Hello, executor!')
    await read_file_in_executor()

asyncio.run(main())

Рекомендация: Всегда отдавайте предпочтение aiofiles для работы с файлами в asyncio, так как это более чистый, читаемый и оптимизированный подход. run_in_executor является более общим, но и более громоздким решением для любых блокирующих задач.