Асинхронные вызовы методов в Python: декораторы и коллбеки
Быстрый ответ
Для реализации асинхронных операций в Python используйте ключевые слова async
и await
в сочетании с модулем asyncio
. Вот простой пример:
import asyncio
async def async_task():
print('Асинхронный процесс запущен, вот в улье вспыхивает суматоха 🐝.')
await asyncio.sleep(1) # Эмуляция задержки, как приготовление кофе ☕︎.
print('Асинхронный процесс завершился ровно как капучино — идеально гладко.')
# Запускаем асинхронное задание:
async def main():
await async_task()
# Приводим в действие механизм asyncio!
asyncio.run(main())
asyncio.run(main())
выполняет роль стартовой точки. Метод main
вызывает функцию async_task
, а ключевое слово await
используется для вызова других async
функций или инициализации операций, поддерживающих asyncio
, что обеспечивает неблокирующее и параллельное выполнение кода.
Async: погружение в детали
Помимо async
/await
есть и другие способы реализации асинхронности – threading
и multiprocessing
. Они обеспечивают другие возможности для асинхронных вызовов и могут быть представлены как супергерои со своими уникальными суперспособностями.
Threading — Флэш⚡ для I/O-интенсивных задач
Подобно Флэшу, мгновенно передвигающемуся из точки А в точку Б, threading
в Python подходит для быстрых I/O-интенсивных операций, позволяя программе выполнять другие задачи во время ожидания IO-операций. Пример использования:
import threading
def async_thread_target():
print("Тут расп unfolds IO-интенсивная реальность. Как чтение захватывающего детектива...")
thr = threading.Thread(target=async_thread_target)
thr.start() # Пусть дело пойдёт своим чередом!
thr.join() # Ожидаем окончания. Ведь мы не хотим остаться в неведении о развязке!
thr.start()
запускает поток, а thr.join()
ожидает его завершения. Проверить активность потока можно с помощью thr.is_alive()
.
Multiprocessing — Халк💪 для CPU-ограниченных задач
Когда речь идет о задачах, ограниченных процессорным временем, на помощь приходит multiprocessing
. Он вскрывает пространство задач быстрее, чем можно произнести "РАЗРУШЕНИЕ!". Для распределения асинхронных вызовов методов подходит multiprocessing.Pool.apply_async
:
from multiprocessing import Pool
def async_process_target(arg):
print(f"Процесс номер {arg} выдаёт отчет, словно служащий регулярно отчитывается перед начальником.")
return arg * arg
if __name__ == '__main__':
pool = Pool()
result = pool.apply_async(async_process_target, (2,))
print(result.get()) # Готово – получено!
Выбор суперспособности
Не уверены, что выбрать из asyncio
, threading
и multiprocessing
? Давайте вместе определим, где что будет более эффективным. Это как подбор подходящей суперособенности.
Когда предпочтительнее использовать asyncio
- Для IO-интенсивных и интернет-ориентированных задач высокого уровня.
- Когда нужно поддерживать множество одновременных соединений, как если бы вы были оператором телефонной станции.
Когда стоит выбрать threading
- Если задачи обычно связаны с ожиданием: чтение с диска и запись на диск.
- Потоки обеспечивают доступ к общей памяти, но стоит учесть Global Interpreter Lock (GIL).
Когда подойдет multiprocessing
- Если вы решаете задачи, ограниченные процессорным временем.
- Этот метод раскрывает все преимущества параллелизма на многопроцессорных системах.
Превосходство Twisted
Библиотека Twisted, хоть и не является встроенной в ядро Python, является настоящим авторитетом в мире асинхронного программирования. Twisted использует объекты Deferred для организации обратных вызовов, как при игре с кошкой и лазерной указкой:
from twisted.internet.defer import Deferred
def callback(result):
print(f"Получен обратный вызов: {result}, как внезапная доставка пиццы 🍕")
deferred = Deferred()
deferred.addCallback(callback)
deferred.callback("Эхо от Twisted!")
С помощью Twisted вы можете организовать множество обратных вызовов и обработчиков ошибок. Также эта библиотека эффективно управляет сетевыми приложениями, требующими неблокирующего обмена данными.
Циклы событий и таймеры Asyncio
Asyncio
предлагает циклы событий и таймеры, позволяющие получить больше контроля над асинхронными операциями:
async def periodic():
while True:
print('Периодическая задача работает, как стрелки древних часов, точно измеряют время.')
await asyncio.sleep(2) # Регулярные паузы длиной 2 секунды
loop = asyncio.get_event_loop()
loop.run_until_complete(periodic())
Здесь loop.run_until_complete()
выполняет задания до их завершения, а asyncio.sleep()
заводит паузы с определенным интервалом.
Визуализация
Чтобы лучше понять асинхронные вызовы в Python, представьте очередь в столовую:
🍽️ [Синхронно]: Берут тарелку, начинают есть, и только после этого следующий человек подходит.
🍽️ 🚀 [Асинхронно]: Берут тарелку и **телепортируются** к столу, начинают есть. Но в этот момент следующий посетитель уже берет свою порцию.
async
методы позволяют не ожидать завершения одного действия перед началом следующего. Он может начаться в тот момент, когда предыдущее ещё выполняется!
import asyncio
async def async_method():
await some_io_task() # 🚀 Телепорт на место выполнения ...
# А следующий посетитель уже подходит к очереди!
Так async
методы функционируют как хорошо отлаженная линия в столовой — быстро и эффективно.
Полезные материалы
- asyncio — Asynchronous I/O — Документация Python 3.12.2 — официальная документация модуля asyncio Python.
- Python Asynchronous Programming – AsyncIO & Async/Await – YouTube — видеоурок по асинхронному программированию на Python с помощью AsyncIO.
- asyncio — Asynchronous I/O, event loop, and concurrency tools — PyMOTW 3 — детальное руководство по асинхронному вводу-выводу, циклам событий и инструментам параллелизма в Python.
- Medium — обзор последовательной и конкурентной обработки с использованием async/await в Python.
- Medium — анализ asyncio в контексте Python и Node.js для создания масштабируемых микросервисов.