← Назад к вопросам

Как писали асинхронный код до появления async/await?

2.0 Middle🔥 221 комментариев
#Python Core#Асинхронность и многопоточность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Асинхронное программирование до async/await: от колбэков к промисам и генераторам

До появления async/await (Python 3.5, 2015) асинхронное программирование было намного сложнее. Разработчики использовали различные подходы: колбэки, промисы, генераторы и различные фреймворки.

1. Колбэки (Callbacks)

Первый способ асинхронного программирования — использование функций обратного вызова.

import threading

def fetch_user(user_id, callback):
    def _fetch():
        import time
        time.sleep(1)
        user = {"id": user_id, "name": "Alice"}
        callback(user)
    
    thread = threading.Thread(target=_fetch)
    thread.start()

def on_user_fetched(user):
    print(f"User: {user}")

fetch_user(1, on_user_fetched)

Проблемы: "Callback Hell" — вложенность становится нечитаемой.

2. Generators + yield

Генераторы позволяли приостанавливать и возобновлять выполнение.

def fetch_user_generator():
    print("Fetching user...")
    user = yield "fetch_user"  # Приостанавливаем
    print(f"User: {user}")
    return user

gen = fetch_user_generator()
request = next(gen)
result = gen.send({"id": 1, "name": "Alice"})

3. Twisted Framework

Один из первых асинхронных фреймворков на Python.

from twisted.internet import defer, reactor

@defer.inlineCallbacks
def fetch_data():
    try:
        response = yield make_request("http://example.com/api")
        print(f"Response: {response}")
    except Exception as e:
        print(f"Error: {e}")
    finally:
        reactor.stop()

reactor.callWhenRunning(fetch_data)
reactor.run()

4. Tornado Web Framework

Популярный фреймворк для асинхронной веб-разработки.

import tornado.ioloop
import tornado.httpclient

class Handler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    def get(self):
        http_client = tornado.httpclient.AsyncHTTPClient()
        
        def handle_response(response):
            self.write(response.body)
            self.finish()
        
        http_client.fetch("http://example.com/api", callback=handle_response)

5. asyncio + yield from (Python 3.3-3.4)

Переходный синтаксис к modern async/await.

import asyncio

@asyncio.coroutine
def fetch_user(user_id):
    yield from asyncio.sleep(1)
    return {"id": user_id, "name": "Alice"}

@asyncio.coroutine
def main():
    user = yield from fetch_user(1)  # yield from вместо await
    print(f"User: {user}")

loop = asyncio.get_event_loop()
loop.run_until_complete(main())

Обработка ошибок до async/await

Большая сложность в каждом колбэке.

def fetch_with_error_handling(callback, error_callback):
    try:
        result = perform_operation()
        callback(result)
    except Exception as e:
        error_callback(e)

Callback Hell пример

# ❌ Ужасная вложенность
def callback_hell():
    def step1(data1):
        def step2(data2):
            def step3(data3):
                print(f"Result: {data1} + {data2} + {data3}")
            fetch_data(step3)
        fetch_data(step2)
    fetch_data(step1)

# ✅ Современный async/await
async def modern():
    data1 = await fetch_data()
    data2 = await fetch_data()
    data3 = await fetch_data()
    print(f"Result: {data1} + {data2} + {data3}")

Параллельное выполнение

До async/await нужно было использовать asyncio.gather или инструменты фреймворков.

import asyncio

@asyncio.coroutine
def old_concurrent():
    tasks = [
        asyncio.ensure_future(fetch_data(1)),
        asyncio.ensure_future(fetch_data(2)),
        asyncio.ensure_future(fetch_data(3)),
    ]
    results = yield from asyncio.gather(*tasks)
    return results

Трудности

  1. Управление ошибками сложное и многословное
  2. Callback Hell — вложенность часто вызывала головную боль
  3. Отладка — сложнее понять стек вызовов
  4. Разные API — каждый фреймворк имел свой способ
  5. Читаемость — асинхронный код выглядел совсем не как синхронный

Преимущества async/await

Когда в Python 3.5 появился async/await:

  • Синтаксис похож на синхронный код
  • Легче читать и писать
  • Встроенная обработка ошибок (try/except)
  • Унифицированный API
  • Намного легче отлаживать

Заключение

До async/await асинхронное программирование в Python требовало глубокого понимания event loop, колбэков и различных фреймворков. Разработчикам приходилось выбирать между Twisted, Tornado, asyncio и другими решениями, каждое с своим синтаксисом. Появление async/await революционизировало разработку, сделав асинхронный код таким же легким для понимания, как синхронный.

Как писали асинхронный код до появления async/await? | PrepBro