Асинхронні методи
Корутини (Coroutines)
Корутини — це асинхронні функції, визначені за допомогою ключового слова async def. Корутини дозволяють призупиняти своє виконання за допомогою ключового слова await, що дозволяє іншим корутинам виконуватися в цей час.
import asyncio
# Визначення асинхронної функції (корутини)
async def main():
print('Hello ...')
# Призупиняємо виконання на 1 секунду
await asyncio.sleep(1)
print('... World!')
# Запуск асинхронної функції main() в циклі подій
asyncio.run(main())Цикл подій (Event Loop)
Цикл подій керує виконанням корутин, задач та інших асинхронних операцій. Виклик asyncio.run() запускає цикл подій і виконує корутину до завершення.
import asyncio
async def main():
print('Hello ...')
await asyncio.sleep(1)
print('... World!')
# Отримання поточного циклу подій
loop = asyncio.get_event_loop()
# Запуск корутини до завершення
loop.run_until_complete(main())
# Закриття циклу подій після завершення всіх задач
loop.close()Задачі (Tasks)
Задачі дозволяють запускати корутини паралельно. Створюються за допомогою asyncio.create_task() або asyncio.ensure_future().
import asyncio
# Визначення корутини, яка буде виконана із затримкою
async def say_after(delay, what):
# Призупиняємо виконання на заданий час
await asyncio.sleep(delay)
print(what)
# Основна корутина
async def main():
# Створюємо задачі для паралельного виконання корутин
task1 = asyncio.create_task(say_after(1, 'hello'))
task2 = asyncio.create_task(say_after(2, 'world'))
# Чекаємо завершення обох задач
await task1
await task2
# Запуск основної корутини
asyncio.run(main())- Метод Task.cancel() - Запитує скасування задачі. Якщо задача ще не завершена, вона буде завершена з викликом виключення CancelledError.
import asyncio
async def main():
task = asyncio.create_task(asyncio.sleep(10))
await asyncio.sleep(1)
task.cancel()
try:
await task
except asyncio.CancelledError:
print("Task was cancelled")
asyncio.run(main())- Метод Task.result() - Повертає результат виконання задачі. Якщо задача завершилася з виключенням, воно буде викликано при виклику result().
import asyncio
async def main():
task = asyncio.create_task(asyncio.sleep(1, result='Completed'))
result = await task
print(result) # Output: Completed
asyncio.run(main())- Метод Task.exception() - Повертає виключення, викликане задачею. Якщо задача завершилася без виключення, повертає None.
import asyncio
async def main():
task = asyncio.create_task(asyncio.sleep(1))
try:
result = await task
except Exception as e:
print(f"Task failed with exception: {e}")
asyncio.run(main())- Метод Task.add_done_callback(callback) - Додає зворотний виклик (callback), який буде викликаний при завершенні задачі.
import asyncio
def callback(future):
print("Task completed")
async def main():
task = asyncio.create_task(asyncio.sleep(1))
task.add_done_callback(callback)
await task
asyncio.run(main())- Метод Task.done() - Повертає True, якщо задача завершена (успішно, з помилкою або була скасована).
import asyncio
async def main():
task = asyncio.create_task(asyncio.sleep(1))
await asyncio.sleep(1.5)
print(task.done()) # Output: True
asyncio.run(main())Ф'ючерси (Futures)
Об'єкти Future представляють собою результати асинхронних операцій, які будуть доступні в майбутньому. Наприклад, вони використовуються для очікування завершення асинхронного завдання.
Основні методи та атрибути
set_result(result):
Встановлює результат для об'єкта Future. Усі корутини, що очікують цей об'єкт, будуть негайно відновлені з цим результатом.
set_exception(exception):
Встановлює виняток для об'єкта Future. Усі корутини, що очікують цей об'єкт, будуть негайно відновлені з цим винятком.
result():
Повертає результат об'єкта Future, якщо він доступний. Якщо операція завершилася з винятком, викличе цей виняток.
exception():
Повертає виняток, якщо він був встановлений, або None, якщо об'єкт Future ще не завершений або завершений успішно.
done():
Повертає True, якщо об'єкт Future завершений (з результатом або винятком).
add_done_callback(callback):
Додає зворотний виклик, який буде викликано при завершенні об'єкта Future.
import asyncio
# Визначення корутини, яка імітує довгу задачу
async def long_running_task():
print('Task started')
# Призупиняємо виконання на 3 секунди
await asyncio.sleep(3)
print('Task finished')
return 'Result'
# Основна корутина
async def main():
# Створюємо ф'ючерс для очікування завершення задачі
future = asyncio.ensure_future(long_running_task())
# Чекаємо завершення задачі і отримуємо результат
result = await future
print(f'Task result: {result}')
# Запуск основної корутини
asyncio.run(main())- Встановлення та отримання результату
import asyncio
async def set_future_result(fut, delay):
await asyncio.sleep(delay)
fut.set_result("Результат Future готовий")
async def main():
loop = asyncio.get_running_loop()
fut = loop.create_future()
asyncio.create_task(set_future_result(fut, 2))
result = await fut
print(result)
asyncio.run(main())- Обробка винятків
import asyncio
async def set_future_exception(fut, delay):
await asyncio.sleep(delay)
fut.set_exception(ValueError("Сталася помилка"))
async def main():
loop = asyncio.get_running_loop()
fut = loop.create_future()
asyncio.create_task(set_future_exception(fut, 2))
try:
result = await fut
except ValueError as e:
print(f"Спіймано виняток: {e}")
asyncio.run(main())- Взаємодія із завданнями
Часто об'єкти Future використовуються в зв'язці із завданнями (Tasks). Коли завдання створюється за допомогою asyncio.create_task(), воно автоматично створює об'єкт Future, який можна використовувати для відстеження і управління станом завдання.
import asyncio
async def example_coroutine():
await asyncio.sleep(1)
return "Результат завдання"
async def main():
task = asyncio.create_task(example_coroutine())
print(await task)
asyncio.run(main())Оператор await
Коли Python зустрічає у коді оператор await, він призупиняє виконання поточної функції і чекає, поки корутина не виконається — поки не завершиться асинхронна функція, на яку посилається корутина.
import asyncio
# Визначення асинхронної функції
async def async_print(text):
print(text)
# Основна асинхронна функція
async def main():
# Використовуємо await для очікування виконання асинхронної функції
await async_print("Hello World")
# Запуск основного циклу подій і виконання корутини main()
asyncio.run(main()) #запускає асинхронну функціюimport asyncio
# Визначення асинхронної функції, яка додає два числа
async def async_add(a, b):
return a + b
# Основна асинхронна функція
async def main():
# Використовуємо await для отримання результату виконання async_add
sum = await async_add(100, 200)
print(sum)
# Запуск основного циклу подій і виконання корутини main()
asyncio.run(main()) #запускає асинхронну функціюМетод run()
Цей метод використовується для запуску асинхронної програми. Він особливо корисний, коли ви хочете запустити асинхронний код із синхронного контексту, наприклад, з основного потоку програми.
Сигнатура:
asyncio.run(async_function(), *, debug=False)- async_function: Корутина, яку необхідно виконати.
- debug: Необов'язковий параметр, що вмикає режим відладки для циклу подій.
Приклад використання:
import asyncio
async def main():
print('Hello')
await asyncio.sleep(1)
print('World')
asyncio.run(main())Метод sleep()
Цей метод використовується, коли вам потрібно призупинити виконання корутини на певний час, не блокуючи при цьому виконання інших корутин.
Сигнатура:
asyncio.sleep(delay, result=None)- delay: Час затримки в секундах (може бути дробним числом).
- result: Опційний результат, який буде повернуто після завершення затримки.
Приклад застосування:
import asyncio
async def main():
print('Start sleeping')
await asyncio.sleep(2)
print('Wake up')
asyncio.run(main())Метод wait()
Цей метод корисний, коли вам потрібно дочекатися завершення кількох асинхронних операцій, але ви хочете мати більш тонкий контроль над процесом очікування.
Сигнатура:
asyncio.wait(fs, *, timeout=None, return_when=ALL_COMPLETED)Де:
- fs: Колекція об'єктів Future або корутин, які необхідно очікувати.
- timeout: Необов'язковий параметр, що вказує максимальний час очікування в секундах. Якщо час очікування минув, метод повертає ті задачі, які були завершені до цього моменту.
- return_when: Умова, що визначає, коли метод повинен завершитися. Можливі значення:
- ALL_COMPLETED: Метод повертає результат, коли всі задачі завершені (за замовчуванням).
- FIRST_COMPLETED: Метод повертає результат, коли завершена перша задача.
- FIRST_EXCEPTION: Метод повертає результат, коли будь-яка задача завершена з винятком.
Очікує завершення кількох задач або корутин. Можна вказати час очікування і умови завершення.
import asyncio
async def say(what, delay):
await asyncio.sleep(delay)
return what
async def main():
task1 = asyncio.create_task(say('hello', 1))
task2 = asyncio.create_task(say('world', 2))
done, pending = await asyncio.wait([task1, task2], timeout=1.5)
for task in done:
print(task.result())
asyncio.run(main())У прикладі вище ми обгортаємо кожну корутину say() в об'єкт Task за допомогою виклику методу create_task(), а потім передаємо список цих тасків у метод wait(). Об'єкти Task дозволяють виконувати корутини паралельно, не очікуючи завершення однієї перед запуском іншої.
Метод gather()
Цей метод особливо корисний, коли вам потрібно запустити кілька асинхронних операцій паралельно і отримати їх результати у вигляді списку.
Сигнатура:
asyncio.gather(*coros_or_futures, return_exceptions=False)Де:
- coros_or_futures: Корутини або об'єкти Future, які повинні бути виконані.
- return_exceptions: Булеве значення, що вказує, чи повинні винятки повертатися як результати. За замовчуванням False.
Приклад використання
import asyncio
async def say_after(delay, what):
await asyncio.sleep(delay)
return what
async def main():
results = await asyncio.gather(
say_after(1, 'hello'),
say_after(2, 'world')
)
print(results)
asyncio.run(main())