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