Функциональность асинхронного программирования Python, или сокращенно асинхронная, позволяет вам писать программы, которые выполняют больше работы, не дожидаясь завершения независимых задач. Библиотека asyncio
включенная в Python, предоставляет инструменты для использования асинхронного режима для обработки дискового или сетевого ввода-вывода без ожидания всего остального.
asyncio
предоставляет два вида API для работы с асинхронными операциями: high-level и low-level . API-интерфейсы высокого уровня наиболее полезны и применимы к самым разнообразным приложениям. Низкоуровневые API-интерфейсы являются мощными, но также сложными и используются реже.
Мы рассмотрим API-интерфейсы высокого уровня в этой статье. В следующих разделах мы рассмотрим наиболее часто используемые высокоуровневые API в asyncio
и покажем, как их можно использовать для обычных операций, связанных с асинхронными задачами.
Если вы совершенно не знакомы с асинхронностью в Python или можете использовать переподготовку о том, как она работает, прочитайте мое введение в асинхронность Python, прежде чем погрузиться в него здесь.
Содержание статьи
Запустите сопрограммы и задачи в Python
Естественно, наиболее распространенное использование asyncio
— это запуск асинхронных частей вашего скрипта Python. Это значит научиться работать с сопрограммами и задачами.
Асинхронные компоненты Python, включая сопрограммы и задачи, могут использоваться только с другими асинхронными компонентами, но не с обычным синхронным Python, поэтому для устранения пробела необходимо asyncio
. Для этого вы используете функцию asyncio.run
:
import asyncio
async def main ():
print («Ожидание 5 секунд»)
для _ в диапазоне (5):
ожидают asyncio.sleep (1)
print (".")
print ("Закончено ожидание.")
asyncio.run (main ())
Запускается main ()
вместе с любыми сопрограммами main ()
запускается и ожидает возврата результата.
Как правило Как правило, программа Python должна иметь только одну инструкцию .run ()
так же как программа Python должна иметь только одну функцию main ()
. Async, если используется небрежно, может затруднить чтение потока управления программой. Наличие единой точки входа в асинхронный код программы предотвращает появление проблем.
Асинхронные функции также можно запланировать как задач или объектов, которые оборачивают сопрограммы и помогают запустите их.
async def my_task ():
do_something ()
task = asyncio.create_task (my_task ())
[1945900k]
task
.
Если у вас есть только одна задача, из которой вы хотите получить результаты, вы можете использовать asyncio.wait_for (task )
чтобы дождаться завершения задачи, а затем использовать task.result ()
чтобы получить ее результат. Но если вы запланировали выполнение ряда задач и хотите дождаться завершения всех из них, используйте asyncio.wait ([task1, task2])
для сбора результатов. (Обратите внимание, что вы можете установить время ожидания для операций, если вы не хотите, чтобы они выполнялись после определенного промежутка времени.)
Управление циклом асинхронных событий в Python
Другое распространенное использование для asyncio
— управление асинхронным циклом событий . Цикл событий — это объект, который выполняет асинхронные функции и обратные вызовы; он создается автоматически при использовании asyncio.run ()
. Как правило, вы хотите использовать только один цикл асинхронных событий для каждой программы, опять же, чтобы обеспечить управляемость.
Если вы пишете более сложное программное обеспечение, такое как сервер, вам потребуется доступ к событию более низкого уровня. петля. Для этого вы можете «снять капюшон» и работать напрямую с внутренностями цикла событий. Но для простых заданий вам не нужно.
Чтение и запись данных с потоками в Python
Лучшими сценариями асинхронной работы являются длительные сетевые операции, где приложение может блокировать ожидание какой-то другой ресурс, чтобы вернуть результат. С этой целью asyncio
предлагает потоки, которые являются высокоуровневыми механизмами для выполнения сетевого ввода-вывода. Это включает в себя работу в качестве сервера для сетевых запросов.
asyncio
использует два класса, StreamReader
и StreamWriter
для чтения и записи из сети. на высоком уровне. Если вы хотите читать из сети, вы должны использовать asyncio.open_connection ()
чтобы открыть соединение. Эта функция возвращает кортеж объектов StreamReader
и StreamWriter
и вы должны использовать методы .read ()
и .write ()
. каждый для связи.
Чтобы получать соединения от удаленных хостов, используйте asyncio.start_server ()
. Функция asyncio.start_server ()
принимает в качестве аргумента функцию обратного вызова, client_connected_cb
которая вызывается всякий раз, когда она получает запрос. Эта функция обратного вызова принимает в качестве аргументов экземпляры StreamReader
и StreamWriter
поэтому вы можете обрабатывать логику чтения / записи для сервера. (См. Здесь пример простого HTTP-сервера, использующего библиотеку asyncio
-driven aiohttp
.)
Синхронизация задач в асинхронном Python
Задачи, как правило, выполняются изолированно, но иногда вы хотите, чтобы они общались друг с другом. asyncio
предоставляет очереди и несколько других механизмов для синхронизации между задачами:
- Очереди : очереди
asyncio
позволяют асинхронным функциям выстраивать Python объекты, которые будут использоваться другими асинхронными функциями — например, для распределения рабочих нагрузок между различными типами функций в зависимости от их поведения. - Примитивы синхронизации : блокировки, события, условия и семафоры в
asyncio
работают как их обычные аналоги Python.
О всех этих методах следует помнить, что они не поточно-ориентированы. Это не проблема для асинхронных задач, выполняющихся в одном цикле событий. Но если вы пытаетесь обмениваться информацией с задачами в другом цикле событий, потоке ОС или процессе, вам потребуется использовать модуль threading
и его объекты для этого.
Кроме того, если вы хотите запустить сопрограммы через границы потоков, используйте функцию asyncio.run_coroutine_threadsafe ()
и передайте цикл событий для использования с ним в качестве параметра.
Приостановить сопрограмму в Python
Другое распространенное использование asyncio
которое обсуждается ниже, ожидает некоторый произвольный промежуток времени внутри сопрограммы. Для этого вы не можете использовать time.sleep ()
иначе вы заблокируете всю программу. Вместо этого используйте asyncio.sleep ()
что позволяет другим сопрограммам продолжать работу.
Используйте низкоуровневую асинхронность в Python
Наконец, если вы считаете, что приложение ваша сборка может потребовать низкоуровневые компоненты asyncio
прежде чем приступить к кодированию, посмотрите вокруг: есть большая вероятность, что кто-то уже создал библиотеку Python с асинхронным питанием, которая делает то, что вам нужно.
Например, если вам нужен асинхронный DNS-запрос, проверьте библиотеку aiodns
а для асинхронных сессий SSH есть asyncSSH
. Ищите PyPI по ключевому слову «async» (плюс другие ключевые слова, относящиеся к задаче) или проверяйте составленный вручную список Awesome Asyncio на предмет идей.
Эта история "Как использовать asyncio в Python" была первоначально опубликована
InfoWorld .