Appearance
Асинхронность в Python с помощью asyncio
Асинхронное программирование в Python предоставляет возможность выполнять несколько задач одновременно, что позволяет значительно улучшить производительность приложений, особенно в случае выполнения ввода-вывода (I/O) операции. Библиотека asyncio
является стандартным способом асинхронного программирования в Python.
Описание работы постановки задачи и решенных примеров
Основные понятия
- Корутина (
coroutine
): Функция, объявленная с помощью ключевого словаasync def
, которая может быть приостановлена и возобновлена в определенных точках. - Событийный цикл (
event loop
): Основной механизм, который управляет выполнением корутин и обработкой событий. - Задача (
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