Skip to content

Асинхронность в Python с помощью asyncio

Асинхронное программирование в Python предоставляет возможность выполнять несколько задач одновременно, что позволяет значительно улучшить производительность приложений, особенно в случае выполнения ввода-вывода (I/O) операции. Библиотека asyncio является стандартным способом асинхронного программирования в Python.

Описание работы постановки задачи и решенных примеров

Основные понятия

  1. Корутина (coroutine): Функция, объявленная с помощью ключевого слова async def, которая может быть приостановлена и возобновлена в определенных точках.
  2. Событийный цикл (event loop): Основной механизм, который управляет выполнением корутин и обработкой событий.
  3. Задача (task): Обёртка над корутиной, которая позволяет отслеживать её состояние и управлять её выполнением.

Пример корутина

python
import asyncio

async def say_hello() -> None:
    print("Hello")
    await asyncio.sleep(1)
    print("World")

Чтобы запустить корутину, необходимо использовать функцию asyncio.run:

python
asyncio.run(say_hello())

Запуск нескольких корутин одновременно

python
import asyncio

async def say_hello() -> None:
    print("Hello")
    await asyncio.sleep(1)
    print("World")

async def say_goodbye() -> None:
    print("Goodbye")
    await asyncio.sleep(1)
    print("Everyone")

async def main() -> None:
    await asyncio.gather(say_hello(), say_goodbye())

asyncio.run(main())

Сравнение скорости работы кода без асинхронного программирования и с асинхронным

Задача без применения асинхронного программирования

Рассмотрим пример выполнения двух долгих операций последовательно:

python
import time

def fetch_data_sync() -> None:
    print("Fetching data...")
    time.sleep(2)
    print("Data fetched")

def process_data_sync() -> None:
    print("Processing data...")
    time.sleep(2)
    print("Data processed")

start_time = time.time()
fetch_data_sync()
process_data_sync()
end_time = time.time()

print(f"Sync operations took {end_time - start_time:.2f} seconds")

Задача применением асинхронного программирования

Теперь рассмотрим тот же пример, но с использованием асинхронного программирования:

python
import asyncio

async def fetch_data_async() -> None:
    print("Fetching data...")
    await asyncio.sleep(2)
    print("Data fetched")

async def process_data_async() -> None:
    print("Processing data...")
    await asyncio.sleep(2)
    print("Data processed")

async def main() -> None:
    await asyncio.gather(fetch_data_async(), process_data_async())

start_time = time.time()
asyncio.run(main())
end_time = time.time()

print(f"Async operations took {end_time - start_time:.2f} seconds")

Объяснение работы

В синхронном примере две функции выполняются последовательно, что занимает 4 секунды. В асинхронном примере обе функции выполняются одновременно, что занимает около 2 секунд.

Сравнение скорости работы кода поточного threading программирования и с асинхронным

Задача применения поточного threading программирования

Рассмотрим пример выполнения двух долгих операций в разных потоках:

python
import time
import threading

def fetch_data_threading() -> None:
    print("Fetching data...")
    time.sleep(2)
    print("Data fetched")

def process_data_threading() -> None:
    print("Processing data...")
    time.sleep(2)
    print("Data processed")

start_time = time.time()
thread1 = threading.Thread(target=fetch_data_threading)
thread2 = threading.Thread(target=process_data_threading)

thread1.start()
thread2.start()

thread1.join()
thread2.join()

end_time = time.time()

print(f"Threading operations took {end_time - start_time:.2f} seconds")

Задача применением асинхронного программирования

Мы уже рассмотрели пример асинхронного программирования выше:

python
import asyncio

async def fetch_data_async() -> None:
    print("Fetching data...")
    await asyncio.sleep(2)
    print("Data fetched")

async def process_data_async() -> None:
    print("Processing data...")
    await asyncio.sleep(2)
    print("Data processed")

async def main() -> None:
    await asyncio.gather(fetch_data_async(), process_data_async())

start_time = time.time()
asyncio.run(main())
end_time = time.time()

print(f"Async operations took {end_time - start_time:.2f} seconds")

Объяснение работы

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

Упражнения

Упражнение 1: Создание и запуск корутины

Создайте корутину, которая выводит "Start", ожидает 1 секунду, затем выводит "End".

python
import asyncio

async def start_end() -> None:
    print("Start")
    await asyncio.sleep(1)
    print("End")

asyncio.run(start_end())

Упражнение 2: Запуск нескольких корутин одновременно

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

python
import asyncio

async def fetch_data() -> None:
    print("Fetching data...")
    await asyncio.sleep(2)
    print("Data fetched")

async def process_data() -> None:
    print("Processing data...")
    await asyncio.sleep(2)
    print("Data processed")

async def main() -> None:
    await asyncio.gather(fetch_data(), process_data())

asyncio.run(main())

Упражнение 3: Асинхронное скачивание данных

Создайте корутину, которая асинхронно скачивает данные с веб-сайта, используя библиотеку aiohttp.

python
import asyncio
import aiohttp

async def fetch_url_async(url: str) -> None:
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            print(await response.text())

asyncio.run(fetch_url_async('https://example.com'))

Упражнение 4: Синхронизация корутин

Создайте две корутины, которые должны выполняться последовательно, используя await.

python
import asyncio

async def task1() -> None:
    print("Task 1 started")
    await asyncio.sleep(1)
    print("Task 1 completed")

async def task2() -> None:
    print("Task 2 started")
    await asyncio.sleep(1

Contacts: teffal@mail.ru