Цикл событийный

Исходный код: Lib/asyncio/events.py, Lib/asyncio/base_events.py


Предисловие

Цикл событий — это ядро любого asyncio приложения. Циклы событий запускают асинхронные задачи и обратные вызовы, выполняют сетевые операции ввода-вывода и запускают подпроцессы.

Разработчики приложений обычно должны использовать высокоуровневые функции asyncio, такие как asyncio.run(), и им редко нужно ссылаться на объект цикла или вызывать его методы. Раздел предназначен в основном для авторов низкоуровневого кода, библиотек и фреймворков, которым требуется более тонкий контроль над поведением цикла событий.

Получение цикла событий

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

asyncio.get_running_loop()

Вернуть запущенный цикл событий в текущем потоке ОС.

Если нет запущенного цикла событий, возникает RuntimeError. Эта функция может вызвана только из корутины или обратного вызова.

Добавлено в версии 3.7.

asyncio.get_event_loop()

Получить текущий цикл событий.

Если в текущем потоке ОС не установлен текущий цикл событий, поток ОС является основным, а set_event_loop() ещё не был вызван, asyncio создаст новый цикл событий и установит его как текущий.

Поскольку у этой функции довольно сложное поведение (особенно при использовании настраиваемых политик цикла событий), использование функции get_running_loop() предпочтительнее, чем get_event_loop() в корутинах и обратных вызовах.

Также рассмотрите возможность использования функции asyncio.run() вместо использования функций нижнего уровня для создания и закрытия цикла событий вручную.

asyncio.set_event_loop(loop)

Установить loop как текущий цикл событий для текущего потока ОС.

asyncio.new_event_loop()

Создать новый объект цикла событий.

Обратите внимание, что поведение функций get_event_loop(), set_event_loop() и new_event_loop() можно изменить с помощью установки настраиваемой политики цикла событий.

Содержание

Данная страница документации содержит следующие разделы:

Методы цикла событий

У циклов событий есть низкоуровневое API для следующих целей:

Запуск и остановка цикла

loop.run_until_complete(future)

Работать, пока не завершится future (экземпляр Future).

Если аргумент — объект корутины, он неявно планируется для запуска как asyncio.Task.

Вернуть результат Future или вызвать его исключение.

loop.run_forever()

Запустить цикл обработки событий, пока не будет вызван stop().

Если stop() вызывается до вызова run_forever(), цикл опрашивает селектор ввода-вывода один раз с нулевым таймаутом, запускает все обратные вызовы, запланированные в ответ на события ввода-вывода (и те, которые уже были запланированы), а затем завершается.

Если stop() вызывается во время работы run_forever(), цикл выполнит текущий пакет обратных вызовов и затем завершится. Обратите внимание, что новые обратные вызовы, запланированные обратными вызовами, в этом случае не будут выполняться; вместо этого они будут запущены при следующем вызове run_forever() или run_until_complete().

loop.stop()

Остановить цикл событий.

loop.is_running()

Вернуть True, если цикл обработки событий выполняется в данный момент.

loop.is_closed()

Вернуть True, если цикл событий был закрыт.

loop.close()

Закрыть цикл событий.

При вызове этой функции цикл не должен выполняться. Все ожидающие обратные вызовы будут отброшены.

Метод очищает все очереди и завершает работу исполнителя, но не дожидается завершения работы исполнителя.

Метод идемпотентен и необратим. Никакие другие методы не должны вызываться после закрытия цикла событий.

coroutine loop.shutdown_asyncgens()

Запланировать закрытие всех открытых в данный момент объектов асинхронного генератора с помощью вызова aclose(). После вызова данного метода цикл событий выдаст предупреждение, если итерируется новый асинхронный генератор. Его следует использовать для надежного завершения всех запланированных асинхронных генераторов.

Обратите внимание, что при использовании asyncio.run() нет необходимости вызывать эту функцию.

Пример:

try:
    loop.run_forever()
finally:
    loop.run_until_complete(loop.shutdown_asyncgens())
    loop.close()

Добавлено в версии 3.6.

Планирование обратных вызовов

loop.call_soon(callback, *args, context=None)

Запланировать callback колбэк, который будет вызываться с аргументами args на следующей итерации цикла событий.

Обратные вызовы (Callbacks) вызываются в том порядке, в котором они зарегистрированы. Каждый обратный вызов будет вызываться ровно один раз.

Необязательный ключевой аргумент context, позволяет указать пользовательский contextvars.Context для выполнения callback. Используется текущий контекст, когда context не предоставлен.

Возвращается экземпляр asyncio.Handle, который можно использовать позже для отмены обратного вызова.

Метод не является потокобезопасным.

loop.call_soon_threadsafe(callback, *args, context=None)

Потокобезопасный вариант call_soon(). Должен использоваться для планирования обратных вызовов из другого потока.

См. раздел документации конкурентность и многопоточность.

Изменено в версии 3.7: Был добавлен параметр context только для ключевых параметров. См. PEP 567 для получения более подробной информации.

Примечание

Большинство функций планирования asyncio не позволяют передавать ключевые аргументы. Для этого используйте functools.partial():

# запланировать "print("Hello", flush=True)"
loop.call_soon(
    functools.partial(print, "Hello", flush=True))

Использование частичных объектов обычно более удобно, чем использование лямбда-выражений, поскольку asyncio может лучше отображать частичные объекты в сообщениях об отладке и ошибках.

Планирование отложенных обратных вызовов

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

loop.call_later(delay, callback, *args, context=None)

Запланировать callback, который будет вызываться после заданного количества секунд delay (может быть либо int, либо float).

Возвращается экземпляр asyncio.TimerHandle, который можно использовать для отмены обратного вызова.

callback будет вызван ровно один раз. Если два обратных вызова запланированы на одно и то же время, порядок, в котором они вызываются, не определён.

Необязательные позиционные args будут переданы обратному вызову при его вызове. Если вы хотите, чтобы callback вызывался с ключевыми аргументами, используйте functools.partial().

Необязательный ключевой аргумент context, позволяет указать пользовательский contextvars.Context для выполнения callback. Используется текущий контекст, когда context не предоставлен.

Изменено в версии 3.7: Был добавлен только ключевой параметр context. См. PEP 567 для получения более подробной информации.

Изменено в версии 3.8: В Python 3.7 и более ранних версиях с реализацией цикла событий по умолчанию delay не могла превышать одного дня. Это было исправлено в Python 3.8.

loop.call_at(when, callback, *args, context=None)

Запланировать callback, который будет вызываться в заданную абсолютную метку времени, when (int или float), используя ту же временную ссылку, что и loop.time().

Поведение данного метода такое же, как у call_later().

Возвращается экземпляр asyncio.TimerHandle, который можно использовать для отмены обратного вызова.

Изменено в версии 3.7: Был добавлен только ключевой параметр context. См. PEP 567 для получения более подробной информации.

Изменено в версии 3.8: В Python 3.7 и ранее с реализацией цикла событий по умолчанию разница между when и текущим временем не могла превышать одного дня. Это было исправлено в Python 3.8.

loop.time()

Возвращает текущее время в виде значения float в соответствии с внутренними монотонными часами цикла событий.

Примечание

Изменено в версии 3.8: В Python 3.7 и более ранних версиях таймауты (относительная delay или абсолютная when) не должны превышать одного дня. Это было исправлено в Python 3.8.

См.также

Функция asyncio.sleep().

Создание Футур и Задач

loop.create_future()

Создать объект asyncio.Future, прикрепленный к циклу событий.

Это предпочтительный способ создания Футур (Futures) в asyncio. Он позволяет сторонним циклам событий предоставлять альтернативные реализации объекта Футуры (с лучшей производительностью или инструментарием).

Добавлено в версии 3.5.2.

loop.create_task(coro, *, name=None)

Запланировать выполнение корутины. Вернуть объект Task.

Сторонние циклы событий могут использовать собственный подкласс Task для взаимодействия. В этом случае тип результата является подклассом Task.

Если указан аргумент name, а не None, он устанавливается как имя задачи с использованием Task.set_name().

Изменено в версии 3.8: Добавлен параметр name.

loop.set_task_factory(factory)

Задать фабрику задач, которая будет использоваться loop.create_task().

Если factoryNone, будет установлена фабрика задач по умолчанию. В противном случае factory должен быть вызываемым с сигнатурой, соответствующей (loop, coro), где loop — это ссылка на активный цикл событий, а coro — объект корутины. Вызываемый объект должен возвращать asyncio.Future-совместимый объект.

loop.get_task_factory()

Вернуть фабрику задач или None, если используется фабрика по умолчанию.

Открытие сетевых подключёний

coroutine loop.create_connection(protocol_factory, host=None, port=None, *, ssl=None, family=0, proto=0, flags=0, sock=None, local_addr=None, server_hostname=None, ssl_handshake_timeout=None, happy_eyeballs_delay=None, interleave=None)

Открыть соединение потокового транспорта с заданным адресом, указанным host и port.

Семейство сокетов может быть AF_INET или AF_INET6 в зависимости от host (или аргумента family, если он указан).

Тип сокета будет SOCK_STREAM.

protocol_factory должен быть вызываемым, возвращающим реализацию протокола asyncio.

Метод попытается установить соединение в фоновом режиме. В случае успеха возвращается пара (transport, protocol).

Хронологический синопсис основной операции выглядит следующим образом:

  1. Соединение установлено, и для него создаётся транспорт.
  2. protocol_factory вызывается без аргументов и ожидается, что он вернёт экземпляр протокола.
  3. Экземпляр протокола связывается с транспортом путём вызова его метода connection_made().
  4. В случае успеха возвращается кортеж (transport, protocol).

Созданный транспорт является зависящим от реализации двунаправленным потоком.

Другие аргументы:

  • ssl: если задано, а не false, создаётся SSL/TLS транспорт (по умолчанию создаётся простой TCP транспорт). Если ssl является объектом ssl.SSLContext, контекст используется для создания транспорта; если sslTrue, используется контекст по умолчанию, возвращенный из ssl.create_default_context().

  • server_hostname устанавливает или переопределяет имя хоста, с которым будет сопоставляться сертификат целевого сервера. Следует передавать, только если ssl не None. По умолчанию используется значение аргумента host. Если host пуст, по умолчанию нет, и вы должны передать значение server_hostname. Если server_hostname является пустой строкой, сопоставление имён хостов отключено (что представляет собой серьезную угрозу безопасности, допускающую потенциальные атаки типа «злоумышленник в середине»).

  • family, proto, flags — это необязательное семейство адресов, протокол и флаги, которые необходимо передать getaddrinfo() для разрешения host. Если задано, все они должны быть целыми числами из соответствующих констант модуля socket.

  • happy_eyeballs_delay, если задан, включает Happy Eyeballs для этого соединения. Это должно быть число с плавающей запятой, представляющее количество времени в секундах для ожидания завершения попытки подключения перед запуском следующей попытки параллельно. Это «Задержка попытки подключения», как определено в RFC 8305. Разумное значение по умолчанию, рекомендованное RFC — 0.25 (250 миллисекунд).

  • interleave управляет переупорядочиванием адресов, когда имя хоста преобразуется в несколько IP-адресов. Если 0 или не указано, переупорядочивание не выполняется, и адреса проверяются в порядке, возвращаемом getaddrinfo(). Если задано положительное целое число, адреса чередуются по семейству адресов, и данное целое число интерпретируется как «Счетчик первого семейства адресов», как определено в RFC 8305. По умолчанию используется 0, если happy_eyeballs_delay не указан, и 1, если он указан.

  • sock, если он задан, должен быть существующим, уже подключённым объектом socket.socket, который будет использоваться транспортом. Если указан sock, не следует указывать ни host, port, family, proto, flags, happy_eyeballs_delay, interleave, ни local_addr.

  • local_addr, если он задан, представляет собой кортеж (local_host, local_port), используемый для локальной привязки сокета. local_host и local_port ищутся с помощью getaddrinfo(), аналогично host и port.

  • ssl_handshake_timeout — (для TLS-соединения) время в секундах, в течение которого нужно дождаться завершения подтверждения TLS, прежде чем разорвать соединение. 60.0 секунда, если None (по умолчанию).

Добавлено в версии 3.8: Добавлены параметры happy_eyeballs_delay и interleave.

Алгоритм Happy Eyeballs: успех с хостами двойного стека. Когда путь и протокол IPv4 сервера работают, но путь и протокол IPv6 сервера не работают, клиентское приложение с двойным стеком испытывает значительную задержку соединения по сравнению с клиентом, работающим только с IPv4. Это нежелательно, потому что из-за этого клиент с двойным стеком будет хуже работать с пользователем. Документ определяет требования к алгоритмам, которые уменьшают эту видимую для пользователя задержку, и предоставляет алгоритм.

Для получения дополнительной информации rfc6555

Добавлено в версии 3.7: Параметр ssl_handshake_timeout.

Изменено в версии 3.6: Параметр сокета TCP_NODELAY установлен по умолчанию для всех TCP-соединений.

Изменено в версии 3.5: Добавлена поддержка SSL/TLS в ProactorEventLoop.

См.также

Функция open_connection() — это альтернативный API высокого уровня. Он возвращает пару (StreamReader, StreamWriter), которые можно использовать непосредственно в коде async/await.

coroutine loop.create_datagram_endpoint(protocol_factory, local_addr=None, remote_addr=None, *, family=0, proto=0, flags=0, reuse_address=None, reuse_port=None, allow_broadcast=None, sock=None)

Примечание

Параметр reuse_address больше не поддерживается, поскольку использование SO_REUSEADDR представляет серьёзную проблему безопасности для UDP. Явная передача reuse_address=True вызовет исключение.

Когда несколько процессов с разными UID назначают сокеты одинаковому адресу сокета UDP с SO_REUSEADDR, входящие пакеты могут случайным образом распределяться между сокетами.

Для поддерживаемых платформ reuse_port может использоваться как замена аналогичной функциональности. С reuse_port вместо него используется SO_REUSEPORT, что специально предотвращает назначение сокетов процессам с разными UID на один и тот же адрес сокета.

Создать дейтаграммное соединение.

Семейство сокетов может быть AF_INET, AF_INET6 или AF_UNIX, в зависимости от host (или аргумента family, если он предоставлен).

Тип сокета будет SOCK_DGRAM.

protocol_factory должен быть вызываемым, возвращающим реализацию протокола.

В случае успеха возвращается кортеж (transport, protocol).

Другие аргументы:

  • local_addr, если он задан, представляет собой кортеж (local_host, local_port), используемый для локальной привязки сокета. local_host и local_port ищутся с помощью getaddrinfo().
  • remote_addr, если он задан, представляет собой кортеж (remote_host, remote_port), используемый для подключения сокета к удаленному адресу. remote_host и remote_port ищутся с помощью getaddrinfo().
  • family, proto, flags — это необязательное семейство адресов, протокол и флаги, которые необходимо передать в getaddrinfo() для разрешения host. Если задано, все они должны быть целыми числами из соответствующих констант модуля socket.
  • reuse_port сообщает ядру разрешить привязку этой конечной точки к тому же порту, к которому привязаны другие существующие конечные точки, при условии, что все они устанавливают данный флаг при создании. Параметр не поддерживается в Windows и некоторых системах Unix. Если константа SO_REUSEPORT не определена, эта возможность не поддерживается.
  • allow_broadcast сообщает ядру разрешить этой конечной точке отправлять сообщения на широковещательный адрес.
  • sock можно дополнительно указать, чтобы использовать уже существующий, уже подключённый объект socket.socket, который будет использоваться транспортом. Если указано, local_addr и remote_addr следует пропустить (должно быть None).

См. примеры Клиентский эхо протокол UDP и Протокол эхо-сервера UDP.

Изменено в версии 3.4.4: Были добавлены параметры family, proto, flags, reuse_address, reuse_port, allow_broadcast и sock.

Изменено в версии 3.8.1: Параметр reuse_address больше не поддерживается из соображений безопасности.

Изменено в версии 3.8: Добавлена поддержка Windows.

coroutine loop.create_unix_connection(protocol_factory, path=None, *, ssl=None, sock=None, server_hostname=None, ssl_handshake_timeout=None)

Создать соединение Unix.

Семейство сокетов будет AF_UNIX; тип сокета будет SOCK_STREAM.

В случае успеха возвращается кортеж (transport, protocol).

path — это имя сокета домена Unix и является обязательным, если не указан параметр sock. Поддерживаются абстрактные сокеты Unix, пути str, bytes и Path.

См. документацию метода loop.create_connection() для получения информации об аргументах этого метода.

Доступность: Unix.

Добавлено в версии 3.7: Параметр ssl_handshake_timeout.

Изменено в версии 3.7: Параметр path теперь может быть путеподобным объектом.

Создание сетевых серверов

coroutine loop.create_server(protocol_factory, host=None, port=None, *, family=socket.AF_UNSPEC, flags=socket.AI_PASSIVE, sock=None, backlog=100, ssl=None, reuse_address=None, reuse_port=None, ssl_handshake_timeout=None, start_serving=True)

Создать TCP-сервер (тип сокета SOCK_STREAM), прослушивающий port адреса host.

Возвращает объект Server.

Аргументы:

  • protocol_factory должен быть вызываемым, возвращающим реализацию протокола.
  • Параметр host может иметь несколько типов, которые определяют, где сервер будет прослушивать:
    • Если host является строкой, TCP-сервер привязан к одному сетевому интерфейсу, указанному host.
    • Если host представляет собой последовательность строк, TCP-сервер привязан ко всем сетевым интерфейсам, указанным в этой последовательности.
    • Если host — пустая строка или None, предполагаются все интерфейсы, и будет возвращен список из нескольких сокетов (скорее всего, один для IPv4, а другой — для IPv6).
  • Для family можно задать значение socket.AF_INET или AF_INET6, чтобы сокет использовал IPv4 или IPv6. Если не установлен, family будет определяться по имени хоста (по умолчанию AF_UNSPEC).
  • flags — это битовая маска для getaddrinfo().
  • sock можно дополнительно указать для использования уже существующего объекта сокета. Если указано, host и port указывать не нужно.
  • backlog — это максимальное количество подключёний в очереди, переданных listen() (по умолчанию 100).
  • ssl может быть установлен на экземпляр SSLContext, чтобы включить TLS по принятым соединениям.
  • reuse_address указывает ядру повторно использовать локальный сокет в состоянии TIME_WAIT, не дожидаясь истечения его естественного тайм- аута. Если не указано, будет автоматически установлено значение True в Unix.
  • reuse_port сообщает ядру разрешить привязку этой конечной точки к тому же порту, к которому привязаны другие существующие конечные точки, при условии, что все они устанавливают данный флаг при создании. Эта опция не поддерживается в Windows.
  • ssl_handshake_timeout — (для TLS-сервера) время в секундах, в течение которого необходимо дождаться завершения рукопожатия TLS, прежде чем разорвать соединение. 60.0 секунды, если None (по умолчанию).
  • start_serving, установленный на True (по умолчанию), заставляет созданный сервер немедленно начать принимать соединения. Если установлено значение False, пользователь должен ждать на Server.start_serving() или Server.serve_forever(), чтобы сервер начал принимать соединения.

Добавлено в версии 3.7: Добавлены параметры ssl_handshake_timeout и start_serving.

Изменено в версии 3.6: Параметр сокета TCP_NODELAY установлен по умолчанию для всех TCP-соединений.

Изменено в версии 3.5: Добавлена поддержка SSL/TLS в ProactorEventLoop.

Изменено в версии 3.5.1: Параметр host может быть последовательностью строк.

См.также

Функция start_server() — это альтернативный API более высокого уровня, который возвращает пару StreamReader и StreamWriter, которые можно использовать в коде async/await.

coroutine loop.create_unix_server(protocol_factory, path=None, *, sock=None, backlog=100, ssl=None, ssl_handshake_timeout=None, start_serving=True)

Аналогичен loop.create_server(), но работает с семейством сокетов AF_UNIX.

path — это имя сокета домена Unix, и он является обязательным, если не указан аргумент sock. Поддерживаются абстрактные сокеты Unix, пути str, bytes и Path.

См. документацию метода loop.create_server() для получения информации об аргументах этого метода.

Доступность: Unix.

Добавлено в версии 3.7: Параметры ssl_handshake_timeout и start_serving.

Изменено в версии 3.7: Параметр path теперь может быть объектом Path.

coroutine loop.connect_accepted_socket(protocol_factory, sock, *, ssl=None, ssl_handshake_timeout=None)

Обернуть уже принятое соединение в пару транспорт/протокол.

Метод может использоваться серверами, которые принимают соединения вне asyncio, но используют asyncio для их обработки.

Параметры:

  • protocol_factory должен быть вызываемым, возвращающим реализацию протокола.
  • sock — это уже существующий объект сокета, возвращенный из socket.accept.
  • ssl можно установить на SSLContext, чтобы включить SSL через принятые соединения.
  • ssl_handshake_timeout — это (для SSL-соединения) время в секундах, в течение которого нужно дождаться завершения подтверждения SSL, прежде чем разорвать соединение. 60.0 секунды, если None (по умолчанию).

Возвращает пару (transport, protocol).

Добавлено в версии 3.7: Параметр ssl_handshake_timeout.

Добавлено в версии 3.5.3.

Передача файлов

coroutine loop.sendfile(transport, file, offset=0, count=None, *, fallback=True)

Отправить file через transport. Возвращает общее количество отправленных байтов.

В методе используется высокопроизводительный os.sendfile(), если он доступен.

file должен быть обычным файловым объектом, открытым в двоичном режиме.

offset указывает, с чего начать чтение файла. Если указано, count — это общее количество байтов для передачи в отличие от отправки файла до достижения EOF. Положение файла всегда обновляется, даже если данный метод вызывает ошибку, и file.tell() можно использовать для получения фактического количества отправленных байтов.

fallback, установленный на True, заставляет asyncio вручную читать и отправлять файл, когда платформа не поддерживает системный вызов sendfile (например, Windows или сокет SSL в Unix).

Поднять SendfileNotAvailableError, если система не поддерживает системный вызов sendfile и fallbackFalse.

Добавлено в версии 3.7.

Обновление TLS

coroutine loop.start_tls(transport, protocol, sslcontext, *, server_side=False, server_hostname=None, ssl_handshake_timeout=None)

Обновить существующее транспортное соединение до TLS.

Вернуть новый транспортный экземпляр, который protocol должен сразу начать использовать после ожидания (await). Экземпляр transport, переданный методу start_tls. Повторно никогда не должен использоваться.

Параметры:

  • экземпляры transport и protocol, возвращаемые такими методами, как create_server() и create_connection().
  • sslcontext: настроенный экземпляр SSLContext.
  • server_side передаёт True при обновлении соединения на стороне сервера (например, созданного create_server()).
  • server_hostname: устанавливает или переопределяет имя хоста, с которым будет сопоставляться сертификат целевого сервера.
  • ssl_handshake_timeout — (для TLS-соединения) время в секундах, в течение которого нужно дождаться завершения рукопожатия TLS, прежде чем разорвать соединение. 60.0 секунд, если None (по умолчанию).

Добавлено в версии 3.7.

Наблюдение за файловыми дескрипторами

loop.add_reader(fd, callback, *args)

Начать мониторинг дескриптора файла fd на предмет доступности для чтения и вызвать callback с указанными аргументами, как только fd станет доступным для чтения.

loop.remove_reader(fd)

Прекратить отслеживать дескриптор файла fd на предмет доступности для чтения.

loop.add_writer(fd, callback, *args)

Начать мониторинг дескриптора файла fd на предмет доступности записи и вызвать callback с указанными аргументами, как только fd станет доступным для записи.

Для для передачи ключевых аргументов callback используйте functools.partial().

loop.remove_writer(fd)

Прекратить отслеживать дескриптор файла fd на предмет доступности записи.

См. также раздел Поддержка платформы для ознакомления с некоторыми ограничениями этих методов.

Непосредственная работа с объектами сокетов

В общем, реализации протокола, использующие API на основе транспорта, такие как loop.create_connection() и loop.create_server(), работают быстрее, чем реализации, которые работают с сокетами напрямую. Однако бывают случаи, когда производительность не критична и удобнее работать напрямую с объектами socket.

coroutine loop.sock_recv(sock, nbytes)

Получить до nbytes от sock. Асинхронная версия socket.recv().

Вернуть полученные данные в виде байтового объекта.

sock должен быть неблокирующим сокетом.

Изменено в версии 3.7: Несмотря на то, что метод всегда был документирован как метод корутин, выпуски до Python 3.7 возвращали Future. Начиная с Python 3.7 это метод async def.

coroutine loop.sock_recv_into(sock, buf)

Получать данные из sock в буфер buf. Смоделирована по методу блокировки socket.recv_into().

Возвращает количество байтов, записанных в буфер.

sock должен быть неблокирующим сокетом.

Добавлено в версии 3.7.

coroutine loop.sock_sendall(sock, data)

Отправить data в сокет sock. Асинхронная версия socket.sendall().

Метод продолжает отправку в сокет до тех пор, пока не будут отправлены все data в данных или пока не возникнет ошибка. None возвращается в случае успеха. При ошибке возникает исключение. Кроме того, невозможно определить, сколько данных, если таковые имеются, было успешно обработано принимающей стороной соединения.

sock должен быть неблокирующим сокетом.

Изменено в версии 3.7: Несмотря на то, что метод всегда документировался как метод корутины, до Python 3.7 он возвращал Future. Начиная с Python 3.7, это метод async def.

coroutine loop.sock_connect(sock, address)

Подключить sock к удаленному сокету по address.

Асинхронная версия socket.connect().

sock должен быть неблокирующим сокетом.

Изменено в версии 3.5.2: address больше не требует решения. sock_connect попытается проверить, разрешен ли уже address, вызвав в socket.inet_pton(). В противном случае для разрешения address будет использоваться loop.getaddrinfo().

coroutine loop.sock_accept(sock)

Принять соединение. Смоделирована по методу блокировки socket.accept().

Сокет должен быть привязан к адресу и прослушивать соединения. Возвращаемое значение — пара (conn, address), где conn — это новый объект сокета, используемый для отправки и получения данных в соединении, а address — это адрес, привязанный к сокету на другом конце соединения.

sock должен быть неблокирующим сокетом.

Изменено в версии 3.7: Несмотря на то, что метод всегда документировался как метод корутины, до Python 3.7 он возвращал Future. Начиная с Python 3.7, это метод async def.

См.также

loop.create_server() и start_server().

coroutine loop.sock_sendfile(sock, file, offset=0, count=None, *, fallback=True)

Если возможно, отправить файл с помощью высокопроизводительного os.sendfile. Возвращает общее количество отправленных байтов.

Асинхронная версия socket.sendfile().

sock должен быть неблокирующим socket.SOCK_STREAM socket.

file должен быть обычным файловым объектом, открытым в двоичном режиме.

offset указывает, с чего начать чтение файла. Если указано, count — это общее количество байтов для передачи в отличие от отправки файла до достижения EOF. Положение файла всегда обновляется, даже если данный метод вызывает ошибку, и file.tell() можно использовать для получения фактического количества отправленных байтов.

fallback, если задано значение True, заставляет asyncio вручную читать и отправлять файл, когда платформа не поддерживает системный вызов sendfile (например, Windows или сокет SSL в Unix).

Поднять SendfileNotAvailableError, если система не поддерживает системный вызов sendfile, а fallbackFalse.

sock должен быть неблокирующим сокетом.

Добавлено в версии 3.7.

DNS

coroutine loop.getaddrinfo(host, port, *, family=0, type=0, proto=0, flags=0)

Асинхронная версия socket.getaddrinfo().

coroutine loop.getnameinfo(sockaddr, flags=0)

Асинхронная версия socket.getnameinfo().

Изменено в версии 3.7: Оба метода getaddrinfo и getnameinfo всегда были задокументированы для возврата корутины (корутины), но до Python 3.7 они фактически возвращали объекты asyncio.Future. Начиная с Python 3.7 оба метода являются корутинами.

Работа с трубами

coroutine loop.connect_read_pipe(protocol_factory, pipe)

Зарегистрировать конец pipe для чтения в цикле событий.

protocol_factory должен быть вызываемым, возвращающим реализацию asyncio протокола.

pipeфайловый объект.

Возвращает пару (transport, protocol), где transport поддерживает интерфейс ReadTransport, а protocol — это объект, созданный с помощью protocol_factory.

В цикле событий SelectorEventLoop pipe устанавливается в неблокирующий режим.

coroutine loop.connect_write_pipe(protocol_factory, pipe)

Зарегистрировать конец pipe для записи в цикле событий.

protocol_factory должен быть вызываемым, возвращающим реализацию протокол asyncio.

pipeфайловый объект.

Возвращает пару (transport, protocol), где transport поддерживает интерфейс WriteTransport, а protocol — это объект, созданный с помощью protocol_factory.

В цикле событий SelectorEventLoop pipe устанавливается в неблокирующий режим.

Примечание

SelectorEventLoop не поддерживает вышеуказанные методы в Windows. Вместо этого для Windows использовать ProactorEventLoop.

См.также

Методы loop.subprocess_exec() и loop.subprocess_shell().

Unix сигналы

loop.add_signal_handler(signum, callback, *args)

Установить callback в качестве обработчика сигнала signum.

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

Поднять ValueError, если номер сигнала недействителен или не обнаруживается. Поднять RuntimeError, если есть проблема с настройкой обработчика.

Используйте functools.partial() для передачи ключевых аргументов для callback.

Как и signal.signal(), эта функция должна вызываться в основном потоке.

loop.remove_signal_handler(sig)

Удалить обработчик сигнала sig.

Вернуть True, если обработчик сигнала был удален, или False, если обработчик не был установлен для данного сигнала.

Доступность: Unix.

См.также

Модуль signal.

Выполнение кода в пулах потоков или процессов

awaitable loop.run_in_executor(исполнитель, функция, аргументы)

Организовать func функции в указанном исполнителе.

Аргумент executor должен быть экземпляром concurrent.futures.Executor. executor по умолчанию используется, если исполнителем является None.

Пример:

import asyncio
import concurrent.futures

def blocking_io():
    # Файловые операции (такие как журналирование) могут блокировать
    # событийный цикл: запустив их в пуле потоков.
    with open('/dev/urandom', 'rb') as f:
        return f.read(100)

def cpu_bound():
    # Связанные с процессором операции блокируют событийного цикла обработки:
    # в общем, лучше запускать их в
    # пуле процессов.
    return sum(i * i for i in range(10 ** 7))

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

    ## Опции:

    # 1. Запустить в исполнителе цикла по умолчанию:
    result = await loop.run_in_executor(
        None, blocking_io)
    print('default thread pool', result)

    # 2. Запустить в пользовательском пуле потоков:
    with concurrent.futures.ThreadPoolExecutor() as pool:
        result = await loop.run_in_executor(
            pool, blocking_io)
        print('custom thread pool', result)

    # 3. Запустить в пользовательском пуле процессов:
    with concurrent.futures.ProcessPoolExecutor() as pool:
        result = await loop.run_in_executor(
            pool, cpu_bound)
        print('custom process pool', result)

asyncio.run(main())

Метод возвращает объект asyncio.Future.

Используйте functools.partial() для передачи ключевых аргументов для func.

Изменено в версии 3.5.3: loop.run_in_executor() больше не настраивает max_workers созданного им исполнителя пула потоков, вместо этого оставляя его исполнителю пула потоков (ThreadPoolExecutor) для установки значения по умолчанию.

loop.set_default_executor(executor)

Установить executor в качестве исполнителя по умолчанию, используемого run_in_executor(). executor должен быть экземпляром ThreadPoolExecutor.

Не рекомендуется, начиная с версии 3.8: Использование исполнителя, не являющегося экземпляром ThreadPoolExecutor, устарело и вызовет ошибку в Python 3.9.

executor должен быть экземпляром concurrent.futures.ThreadPoolExecutor.

API обработки ошибок

Позволяет настроить обработку исключений в цикле событий.

loop.set_exception_handler(handler)

Установить handler как новый обработчик исключений цикла событий.

Если handler является None, будет установлен обработчик исключений по умолчанию. В противном случае handler должен быть вызываемым с сигнатурой, соответствующей (loop, context), где loop — это ссылка на активный цикл событий, а context — это объект dict, содержащий сведения об исключении (подробные сведения о контексте см. в документации call_exception_handler()).

loop.get_exception_handler()

Вернуть текущий обработчик исключений или None, если пользовательский обработчик исключений не был установлен.

Добавлено в версии 3.5.2.

loop.default_exception_handler(context)

Обработчик исключений по умолчанию.

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

context параметр имеет то же значение, что и в call_exception_handler().

loop.call_exception_handler(context)

Вызов текущего обработчика исключения цикла событий.

context — это объект dict, содержащий следующие ключи (новые ключи могут быть введены в будущих версиях Python):

  • «message»: сообщение об ошибке;
  • «exception» (необязательно): объект исключения;
  • «future» (необязательно): экземпляр asyncio.Future;
  • «handle» (необязательно): экземпляр asyncio.Handle;
  • «protocol» (необязательно): экземпляр Протокола;
  • «transport» (необязательно): экземпляр Транспорта;
  • «socket» (необязательно): экземпляр socket.socket.

Примечание

Метод не следует перегружать в циклах событий подкласса. Для настраиваемой обработки исключений использовать метод set_exception_handler().

Включение режима отладки

loop.get_debug()

Получить режим отладки (bool) цикла событий.

Значение по умолчанию — True, если для переменной среды PYTHONASYNCIODEBUG задана непустая строка, в противном случае — False.

loop.set_debug(enabled: bool)

Установить режим отладки цикла событий.

Изменено в версии 3.7: Новый параметр командной строки -X dev теперь также можно использовать для включения режима отладки.

Запущенные подпроцессы

Методы, описанные в этом подразделе, относятся к низкоуровневым. В обычном коде async/await рассмотрите возможность использования вместо них вспомогательных функций высокого уровня asyncio.create_subprocess_shell() и asyncio.create_subprocess_exec().

Примечание

Цикл событий asyncio в Windows по умолчанию не поддерживает подпроцессы. Подробнее см. Поддержка подпроцессов в Windows.

coroutine loop.subprocess_exec(protocol_factory, *args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)

Создать подпроцесс из одного или нескольких строковых аргументов, указанных в args.

args должен быть списком строк, представленных:

Первая строка указывает исполняемый файл программы, а остальные строки указывают аргументы. Вместе строковые аргументы образуют argv программы.

Это похоже на класс стандартной библиотеки subprocess.Popen, вызываемый с shell=False и списком строк, переданных в качестве первого аргумента; однако, если Popen принимает единственный аргумент, который является списком строк, subprocess_exec принимает несколько строковых аргументов.

protocol_factory должен быть вызываемым, возвращающим подкласс класса asyncio.SubprocessProtocol.

Прочие параметры:

  • stdin может быть любым из них:

    • файловый объект, представляющий канал, который должен быть подключён к стандартному входному потоку подпроцесса с использованием connect_write_pipe()
    • константа subprocess.PIPE (по умолчанию), которая создаст новый канал и соединит его
    • значение None, которое заставит подпроцесс наследовать файловый дескриптор этого процесса
    • константа subprocess.DEVNULL, которая указывает, что будет использоваться специальный файл os.devnull
  • stdout может быть любым из них:

    • файловый объект, представляющий канал, который должен быть подключён к стандартному потоку вывода подпроцесса с использованием connect_write_pipe()
    • константа subprocess.PIPE (по умолчанию), которая создаст новый канал и соединит его
    • значение None, которое заставит подпроцесс наследовать дескриптор файла от этого процесса
    • константа subprocess.DEVNULL, которая указывает, что будет использоваться специальный файл os.devnull
  • stderr может быть любым из них:

    • файловый объект, представляющий канал, который должен быть подключён к стандартному потоку ошибок подпроцесса с использованием connect_write_pipe()
    • константа subprocess.PIPE (по умолчанию), которая создаст новый канал и соединит его
    • значение None, которое заставит подпроцесс наследовать файловый дескриптор этого процесса
    • константа subprocess.DEVNULL, которая указывает, что будет использоваться специальный файл os.devnull
    • константа subprocess.STDOUT, которая соединит стандартный поток ошибок со стандартным потоком вывода процесса
  • Все остальные ключевые аргументы передаются в subprocess.Popen без интерпретации, за исключением bufsize, universal_newlines, shell, text, encoding и errors которые вообще не должны указываться.

    API подпроцесса asyncio не поддерживает декодирование потоков как текста. bytes.decode() можно использовать для преобразования байтов, возвращаемых из потока, в текст.

См. конструктор класса subprocess.Popen для документации по другим аргументам.

Возвращает пару (transport, protocol), где transport соответствует базовому классу asyncio.SubprocessTransport, а protocol — объект, экземпляр которого был создан с помощью protocol_factory.

coroutine loop.subprocess_shell(protocol_factory, cmd, *, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)

Создать подпроцесс из cmd, который может быть строкой str или bytes, закодированной в кодировке файловой системы, используя синтаксис «оболочки» платформы.

Это похоже на класс стандартной библиотеки subprocess.Popen, который называется shell=True.

protocol_factory должен быть вызываемым, возвращающим подкласс класса SubprocessProtocol.

См. subprocess_exec() для получения дополнительных сведений об оставшихся аргументах.

Возвращает пару (transport, protocol), где transport соответствует базовому классу SubprocessTransport, а protocol — это объект, созданный с помощью protocol_factory.

Примечание

Приложение несёт ответственность за то, чтобы все пробелы и специальные символы были указаны в кавычках, чтобы избежать уязвимостей инъекция оболочки. Функцию shlex.quote() можно использовать для правильного экранирования пробелов и специальных символов в строках, которые будут использоваться для создания команд оболочки.

Дескрипторы обратного вызова

class asyncio.Handle

Объект-оболочка обратного вызова, возвращаемый loop.call_soon(), loop.call_soon_threadsafe().

cancel()

Отменить обратный вызов. Если обратный вызов уже был отменён или выполнен, метод не действует.

cancelled()

Вернуть True, если обратный вызов был отменен.

Добавлено в версии 3.7.

class asyncio.TimerHandle

Объект-оболочка обратного вызова, возвращаемый loop.call_later() и loop.call_at().

Класс является подклассом Handle.

when()

Вернуть запланированное время обратного вызова как float секунд.

Время — это абсолютная временная метка с той же привязкой ко времени, что и loop.time().

Добавлено в версии 3.7.

Server объекты

Server объекты создаются функциями loop.create_server(), loop.create_unix_server(), start_server() и start_unix_server().

Не создавайте экземпляр класса напрямую.

class asyncio.Server

Объекты Server — асинхронные менеджеры контекста. При использовании в операторе async with гарантируется, что объект Server закрыт и не принимает новые соединения после завершения оператора async with:

srv = await loop.create_server(...)

async with srv:
    # некоторый код

# В данный момент srv закрыт и больше не принимает новые подключения.

Изменено в версии 3.7: Объект Server — это асинхронный менеджер контекста, начиная с Python 3.7.

close()

Прекращение обслуживания: закрыть прослушивающие сокеты и установить для атрибута sockets значение None.

Сокеты, которые представляют существующие входящие клиентские соединения, остаются открытыми.

Сервер закрывается асинхронно, использовать корутину wait_closed(), чтобы дождаться закрытия сервера.

get_loop()

Вернуть цикл событий, связанный с серверным объектом.

Добавлено в версии 3.7.

coroutine start_serving()

Начать принимать подключения.

Метод идемпотентен, поэтому его можно вызывать, когда сервер уже обслуживает.

start_serving только для ключевого параметра для loop.create_server() и asyncio.start_server() позволяет создать объект Server, который изначально не принимает соединения. В этом случае можно использовать Server.start_serving() или Server.serve_forever(), чтобы сервер начал принимать соединения.

Добавлено в версии 3.7.

coroutine serve_forever()

Начать принимать соединения, пока корутина не будет отменена. Отмена задачи serve_forever приводит к закрытию сервера.

Метод можно вызвать, если сервер уже принимает соединения. На один объект Server может существовать только одна задача serve_forever.

Пример:

async def client_connected(reader, writer):
    # Взаимодействие клиента с потоками
    # читения/записи. Например:
    await reader.readline()

async def main(host, port):
    srv = await asyncio.start_server(
        client_connected, host, port)
    await srv.serve_forever()

asyncio.run(main('127.0.0.1', 0))

Добавлено в версии 3.7.

is_serving()

Вернуть True, если сервер принимает новые соединения.

Добавлено в версии 3.7.

coroutine wait_closed()

Дождаться завершения метода close().

sockets

Список объектов socket.socket, которые прослушивает сервер.

Изменено в версии 3.7: До Python 3.7 Server.sockets использовался для непосредственного возврата внутреннего списка серверных сокетов. В 3.7 возвращается копия этого списка.

Реализации цикла событий

asyncio поставляется с двумя разными реализациями цикла событий: SelectorEventLoop и ProactorEventLoop.

По умолчанию asyncio настроен на использование SelectorEventLoop в Unix и ProactorEventLoop в Windows.

class asyncio.SelectorEventLoop

Цикл событий на основе модуля selectors.

Использует наиболее эффективный селектор, доступный для данной платформы. Также можно вручную настроить точную реализацию селектора, который будет использоваться:

import asyncio
import selectors

selector = selectors.SelectSelector()
loop = asyncio.SelectorEventLoop(selector)
asyncio.set_event_loop(loop)

Доступность: Unix, Windows.

class asyncio.ProactorEventLoop

Цикл событий для Windows, использующий «порты завершения ввода-вывода» (IOCP).

Доступность: Windows.

class asyncio.AbstractEventLoop

Абстрактный базовый класс для асинхронных циклов событий.

В разделе Методы цикла событий перечислены все методы, которые должна была определять альтернативная реализация AbstractEventLoop.

Примеры

Обратите внимание, что все примеры в этом разделе целенаправленно рассказывают, как использовать API-интерфейсы низкоуровневого цикла событий, такие как loop.run_forever() и loop.call_soon(). Современные приложения asyncio редко нужно писать таким образом; рассмотрите возможность использования функций высокого уровня, таких как asyncio.run().

«Привет, мир» с call_soon()

Пример использования метода loop.call_soon() для планирования обратного вызова. Обратный вызов отображает "Hello World", а затем останавливает цикл событий:

import asyncio

def hello_world(loop):
    """Коллбэк печатает 'Hello World' и останавливает событийный цикл"""
    print('Hello World')
    loop.stop()

loop = asyncio.get_event_loop()

# Запланировать вызов hello_world()
loop.call_soon(hello_world, loop)

# Блокирующий вызов прерываемый loop.stop()
try:
    loop.run_forever()
finally:
    loop.close()

См.также

Аналогичный пример Hello World, созданный с помощью корутины и функции run().

Отобразите текущую дату с помощью call_later()

Пример обратного вызова, отображающего текущую дату каждую секунду. Обратный вызов использует метод loop.call_later() для перепланирования себя через 5 секунд, а затем останавливает цикл событий:

import asyncio
import datetime

def display_date(end_time, loop):
    print(datetime.datetime.now())
    if (loop.time() + 1.0) < end_time:
        loop.call_later(1, display_date, end_time, loop)
    else:
        loop.stop()

loop = asyncio.get_event_loop()

# Запланировать первый вызов display_date()
end_time = loop.time() + 5.0
loop.call_soon(display_date, end_time, loop)

# Блокировка вызова прервана loop.stop()
try:
    loop.run_forever()
finally:
    loop.close()

См.также

Аналогичный пример текущей даты, созданный с помощью корутины и функции run().

Следите за файловым дескриптором на предмет событий чтения

Подождать, пока файловый дескриптор получит некоторые данные с помощью метода loop.add_reader(), а затем закрыть цикл обработки событий:

import asyncio
from socket import socketpair

# Создаёт пару связанных файловых дескрипторов
rsock, wsock = socketpair()

loop = asyncio.get_event_loop()

def reader():
    data = rsock.recv(100)
    print("Received:", data.decode())

    # Мы закончили: отменить регистрацию файлового дескриптора
    loop.remove_reader(rsock)

    # Отстановить событийный цикл
    loop.stop()

# Зарегистрировать дескриптор файла для события чтения
loop.add_reader(rsock, reader)

# Имитировать приём данных из сети
loop.call_soon(wsock.send, 'abc'.encode())

try:
    # Запуск событийного цикла
    loop.run_forever()
finally:
    # Завершаем работу. Закрыть сокеты и цикл обработки событий.
    rsock.close()
    wsock.close()
    loop.close()

См.также

Установить обработчики сигналов для SIGINT и SIGTERM

(Пример signals работает только в Unix.)

Зарегистрировать обработчики сигналов SIGINT и SIGTERM с помощью метода loop.add_signal_handler():

import asyncio
import functools
import os
import signal

def ask_exit(signame, loop):
    print("got signal %s: exit" % signame)
    loop.stop()

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

    for signame in {'SIGINT', 'SIGTERM'}:
        loop.add_signal_handler(
            getattr(signal, signame),
            functools.partial(ask_exit, signame, loop))

    await asyncio.sleep(3600)

print("Event loop running for 1 hour, press Ctrl+C to interrupt.")
print(f"pid {os.getpid()}: send SIGINT or SIGTERM to exit.")

asyncio.run(main())