Асинхронні методи

Корутини (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())
2015-2026 © SumyNikNet