Сообщить об ошибке.

Функция to_thread() модуля asyncio в Python

Асинхронное выполнение блокирующих операций в asyncio

Синтаксис:

import asyncio

# новое в Python 3.9
await asyncio.to_thread(func, /, *args, **kwargs)

Параметры:

  • func - функция, которая может заблокировать цикл событий.
  • *args - аргументы func,
  • **kwargs - ключевые аргументы func.

Возвращаемое значение:

  • функцию func, обернутую в задачу.

Описание:

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

Любые *args и **kwargs, переданные в функции asyncio.to_thread(), напрямую передаются в запускаемую func. Кроме того, текущий contextvars.Context распространяется, позволяя доступ к контекстным переменным из потока цикла событий в отдельном потоке.

Функция asyncio.to_thread() возвращает сопрограмму, для которой можно ожидать результаты функции func.

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

Примечание. Из-за GIL, функция asyncio.to_thread() обычно используется только для функции, связанных с вводом/выводом. Однако для модулей расширения, которые обходят GIL или альтернативные реализации Python, у которых его нет, функция asyncio.to_thread() также может использоваться для функций, связанных с процессором.

Новое в Python 3.9

Пример запуска блокирующей операции в отдельном потоке:

В примере запускается блокирующая функция time.sleep(), которая может быть заменена любой другой блокирующей операцией, например чтение/запись файла.

Непосредственный вызов функции blocking_io() в любой сопрограмме заблокирует цикл событий на время его выполнения, что приведет к дополнительной 1 секунде времени выполнения. Чтобы этого не происходило, используя функция asyncio.to_thread(), которая запускает ее в отдельном потоке, не блокируя цикл обработки событий.

import asyncio, time

def blocking_io():
    print(f"Запуск `blocking_io()`: {time.strftime('%X')}")
    # Функция `time.sleep()` может быть заменена любой другой
    #  блокирующей операцией, например файловым вводом/выводом.
    time.sleep(1)
    print(f"Функция `blocking_io()` завершена: {time.strftime('%X')}")

async def main():
    print(f"Старт цикла событий: {time.strftime('%X')}")

    await asyncio.gather(
        asyncio.to_thread(blocking_io),
        asyncio.sleep(1))

    print(f"Завершение цикла событий: {time.strftime('%X')}")

asyncio.run(main())

# Старт цикла событий: 09:33:04
# Запуск `blocking_io()`: 09:33:04
# Функция `blocking_io()` завершена: 09:33:05
# Завершение цикла событий: 09:33:05