WEBYK WEBYK Індивідуальні OnLine уроки з web технологій
+38 093 766 39 11
oleggpann@gmail.com

Асинхронне програмування в Python: Від async/await до реальних застосувань

### Ця стаття є повним посібником з асинхронного програмування в Python. Ми розберемося, що таке асинхронність, навіщо вона потрібна, і як використовувати сучасний синтаксис async/await та бібліотеку asyncio для створення швидких та ефективних I/O-орієнтованих застосунків. Стаття містить практичні приклади коду для порівняння синхронного та асинхронного підходів. ---

У світі сучасних веб-застосунків швидкість відгуку є критично важливою. Користувачі не люблять чекати. Часто програми витрачають левову частку часу не на обчислення, а на очікування: відповіді від бази даних, завантаження файлу з мережі, результату від зовнішнього API. Це так звані операції вводу-виводу (I/O). Традиційний, синхронний підхід змушує програму "завмирати" на час очікування. Уявіть, що вам потрібно завантажити 100 зображень з Інтернету. Синхронний код завантажить перше, дочекається його повного завантаження, потім перейде до другого, і так далі. Весь цей час процесор простоюватиме. Асинхронне програмування пропонує елегантне вирішення цієї проблеми, дозволяючи виконувати інші корисні завдання, поки одне з них очікує на завершення I/O операції. У цій статті ми зануримося у світ asyncio — вбудованої бібліотеки Python для асинхронного програмування — і навчимося писати неблокуючий, високопродуктивний код.

Що таке асинхронне програмування?
**Асинхронне програмування** — це парадигма, за якої завдання можуть виконуватися незалежно одне від одного. Коли одне завдання починає операцію, що вимагає очікування (наприклад, мережевий запит), програма не блокується, а перемикається на виконання іншого завдання. Щойно перше завдання отримує результат, програма повертається до його обробки. Це схоже на те, як працює шеф-кухар на кухні. Замість того, щоб поставити варитися суп і дивитися на нього 40 хвилин (синхронний підхід), він ставить суп, а поки той вариться, починає нарізати овочі для салату, ставити стейк у духовку тощо (асинхронний підхід). Він ефективно використовує свій час, перемикаючись між завданнями.

Чим це відрізняється від багатопотоковості? Хоча і багатопотоковість (multithreading), і асинхронність вирішують проблему простою, вони роблять це по-різному:

* **Багатопотоковість:** Операційна система керує кількома потоками виконання. Перемикання між потоками є "витісняючим" і може відбуватися в будь-який момент, що створює ризики станів гонитви (race conditions) і потребує складних механізмів блокування (locks).

* **Асинхронність:** Працює в одному потоці. Перемикання між завданнями є "кооперативним" — завдання саме віддає керування в чітко визначених точках (зазвичай через await). Це робить код простішим для розуміння та усуває більшість проблем, пов'язаних із синхронізацією.

Ключові концепції asyncio Бібліотека asyncio надає інфраструктуру для написання асинхронного коду. Розглянемо її основні компоненти.

Корутини (Coroutines)

Корутина — це основна одиниця виконання в asyncio. Це функція, виконання якої можна призупинити та відновити. В Python корутини створюються за допомогою синтаксису async def.
import asyncio

async def my_coroutine():
    print("Початок виконання корутини")
    await asyncio.sleep(1) # Призупиняємо виконання на 1 секунду
    print("Корутина завершена")
Виклик такої функції не виконує її код одразу, а повертає об'єкт корутини.

Цикл подій (Event Loop)

Цикл подій — це ядро asyncio. Він відповідає за керування та виконання корутин. Він працює як диспетчер: запускає завдання, стежить за операціями вводу-виводу і, коли завдання готове до продовження, повертає йому керування.

Конструкція async/await

Це синтаксичний цукор, який робить роботу з корутинами інтуїтивно зрозумілою.

* async def — оголошує функцію як корутину.

* await — призупиняє виконання поточної корутини, передає керування циклу подій і чекає на завершення іншої корутини (або об'єкта awaitable). Використовувати await можна лише всередині async def функції.

Практичний приклад: Синхронний vs Асинхронний код Давайте порівняємо два підходи на реальному завданні: завантаженні даних з кількох URL-адрес.

Синхронний підхід (блокуючий)

Для цього прикладу використаємо популярну бібліотеку requests.
import requests
import time

def fetch_url(url):
    print(f"Завантажую {url}...")
    requests.get(url)
    print(f"Завантажено {url}")

def main_sync():
    urls = [
        "https://www.python.org",
        "https://www.google.com",
        "https://github.com",
    ]
    start_time = time.time()
    for url in urls:
        fetch_url(url)
    end_time = time.time()
    print(f"Синхронне виконання зайняло {end_time - start_time:.2f} секунд")

main_sync()

# Можливий вивід:
# Завантажую https://www.python.org...
# Завантажено https://www.python.org
# Завантажую https://www.google.com...
# Завантажено https://www.google.com
# Завантажую https://github.com...
# Завантажено https://github.com
# Синхронне виконання зайняло 2.15 секунд
Як бачимо, запити виконуються послідовно. Загальний час приблизно дорівнює сумі часів виконання кожного запиту.

Асинхронний підхід з asyncio та aiohttp

Стандартна бібліотека requests є блокуючою. Для асинхронних HTTP-запитів ми використаємо aiohttp.
import asyncio
import aiohttp
import time

async def fetch_url_async(session, url):
    print(f"Завантажую {url}...")
    async with session.get(url) as response:
        # Ми можемо тут обробити response.text(), але для чистоти експерименту
        # просто очікуємо на отримання відповіді
        await response.read()
        print(f"Завантажено {url}")

async def main_async():
    urls = [
        "https://www.python.org",
        "https://www.google.com",
        "https://github.com",
    ]
    start_time = time.time()
    async with aiohttp.ClientSession() as session:
        # Створюємо список завдань для одночасного виконання
        tasks = [fetch_url_async(session, url) for url in urls]
        # Запускаємо всі завдання і чекаємо їх завершення
        await asyncio.gather(*tasks)
    end_time = time.time()
    print(f"Асинхронне виконання зайняло {end_time - start_time:.2f} секунд")

# Запускаємо головну асинхронну функцію
asyncio.run(main_async())

# Можливий вивід:
# Завантажую https://www.python.org...
# Завантажую https://www.google.com...
# Завантажую https://github.com...
# Завантажено https://www.google.com
# Завантажено https://github.com
# Завантажено https://www.python.org
# Асинхронне виконання зайняло 0.85 секунд
Зверніть увагу: всі запити стартували майже одночасно. Загальний час виконання приблизно дорівнює часу найдовшого запиту, а не їх сумі. Це і є головна перевага асинхронності для I/O-завдань.

Коли варто використовувати асинхронність? Асинхронний підхід є ідеальним для **I/O-bound** завдань, тобто завдань, де основний час витрачається на очікування ресурсів:

* Мережеві запити (веб-скрапінг, робота з API).

* Робота з базами даних.

* Читання/запис файлів на диск.

* Високонавантажені веб-сервери, що обробляють тисячі одночасних з'єднань. Однак, для **CPU-bound** завдань (складні математичні обчислення, обробка зображень, машинне навчання) асинхронність не дасть приросту продуктивності, оскільки процесор постійно зайнятий. Для таких завдань краще підходить багатопроцесорність (модуль multiprocessing).

Висновок Асинхронне програмування в Python завдяки asyncio та синтаксису async/await перетворилося з нішової технології на потужний інструмент для створення швидких та масштабованих додатків. Розуміння його принципів дозволяє ефективно вирішувати проблеми, пов'язані з очікуванням, та значно покращити продуктивність ваших програм. Почніть експериментувати з asyncio вже сьогодні, і ви побачите, наскільки швидшим може стати ваш код. Якщо у вас виникли питання щодо впровадження асинхронності у ваші проєкти або потрібна консультація, звертайтеся за адресою: **isholegg@gmail.com**. ---

Ключові слова асинхронне програмування, Python, asyncio, async/await, корутини, event loop, aiohttp, оптимізація продуктивності, неблокуючий ввід/вивід, Python для вебу, паралельне виконання, I/O-bound.

Meta Дізнайтеся, як асинхронне програмування в Python з asyncio та async/await може кардинально прискорити ваші I/O-застосунки. Повний посібник з теорією, практичними прикладами коду та порадами щодо використання.

Якщо у вас виникли питання, вбо ви бажаєте записатися на індивідуальний урок, замовити статтю (інструкцію) або придбати відеоурок, пишіть нам на:
скайп: olegg.pann
telegram, viber - +380937663911
додавайтесь у телеграм-канал: t.me/webyk
email: oleggpann@gmail.com
ми у fb: www.facebook.com/webprograming24
Обов`язково оперативно відповімо на усі запитіння


Поділіться в соцмережах



Подобные статьи:


facebook
×
Підришіться на цікаві пости.
Підписатись