← Назад к вопросам
Расскажи про эволюцию асинхронности
2.0 Middle🔥 71 комментариев
#DevOps и инфраструктура#Django
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Эволюция асинхронности в программировании
Асинхронность — это парадигма программирования, позволяющая выполнять долгие операции без блокировки основного потока выполнения. История её развития показывает эволюцию от простых callback'ов к современным async/await.
Этап 1: Синхронность (классический подход)
# Синхронный код — блокирует выполнение
import time
def fetch_data():
"""Долгая операция (I/O)"""
time.sleep(2) # Имитация сетевого запроса
return "Data from server"
print("Начало")
data = fetch_data() # Блокирует на 2 секунды
print(f"Данные: {data}")
print("Конец")
# Время выполнения: 2+ секунды
# Программа полностью заморожена во время wait_response
Проблема: при многих операциях программа становится очень медленной.
Этап 2: Callbacks (обратные вызовы)
JavaScript (Node.js)
// Callback-стиль (1990-2000е)
function fetchData(callback) {
// Имитация асинхронной операции
setTimeout(() => {
callback('Data from server');
}, 2000);
}
fetchData((data) => {
console.log('Данные:', data);
});
console.log('Это выведется первым');
// Вывод:
// Это выведется первым
// [2 сек ожидания]
// Данные: Data from server
Проблема: Callback Hell (ад обратных вызовов)
// Вложенные callbacks становятся нечитаемыми
fetchUser((user) => {
fetchPosts(user.id, (posts) => {
fetchComments(posts[0].id, (comments) => {
fetchReplies(comments[0].id, (replies) => {
console.log(replies);
// Кошмар!
});
});
});
});
Этап 3: Promises (обещания)
JavaScript (ES6, 2015)
// Promise — объект, представляющий будущее значение
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Data from server');
}, 2000);
});
}
// Цепочка .then() вместо вложенных callbacks
fetchData()
.then(data => {
console.log('Данные:', data);
return fetchPosts(data);
})
.then(posts => {
console.log('Посты:', posts);
return fetchComments(posts[0].id);
})
.then(comments => {
console.log('Комментарии:', comments);
})
.catch(error => {
console.error('Ошибка:', error);
});
Преимущества Promise:
- Линейное читаемое выполнение
- Встроенная обработка ошибок через
.catch() - Гибкость: Promise может использоваться многими способами
// Параллельное выполнение несколько Promises
Promise.all([
fetchUser(),
fetchPosts(),
fetchComments()
])
.then(([user, posts, comments]) => {
console.log('Всё загружено');
});
// Ожидание первого успешного
Promise.race([
fetchFromServer1(),
fetchFromServer2(),
fetchFromServer3()
])
.then(firstResult => {
console.log('Первый результат:', firstResult);
});
Этап 4: Async/Await (синтаксический сахар поверх Promise)
JavaScript (ES2017) и Python (3.5+)
// async/await выглядит как синхронный код, но работает асинхронно
async function getFullData() {
try {
const user = await fetchUser(); // Ждём, как в синхронном коде
console.log('Пользователь:', user);
const posts = await fetchPosts(user.id);
console.log('Посты:', posts);
const comments = await fetchComments(posts[0].id);
console.log('Комментарии:', comments);
return { user, posts, comments };
} catch (error) {
console.error('Ошибка:', error);
}
}
getFullData();
Python версия
# Python (3.5+)
import asyncio
import aiohttp
async def fetch_data(url):
"""Асинхронный fetch"""
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.json()
async def main():
user = await fetch_data('https://api.example.com/user')
print('Пользователь:', user)
posts = await fetch_data(f'https://api.example.com/posts/{user["id"]}')
print('Посты:', posts)
# Запуск асинхронного кода
asyncio.run(main())
Преимущества async/await:
- Выглядит как обычный синхронный код
- Легче понять логику выполнения
- Обработка ошибок через try/except
Этап 5: Event Loops (цикл событий)
Как асинхронность работает на самом деле
# Python asyncio использует Event Loop
import asyncio
async def task1():
print("Task 1 начало")
await asyncio.sleep(2)
print("Task 1 конец")
async def task2():
print("Task 2 начало")
await asyncio.sleep(1)
print("Task 2 конец")
async def task3():
print("Task 3 начало")
await asyncio.sleep(0.5)
print("Task 3 конец")
async def main():
# Запуск всех задач параллельно
await asyncio.gather(
task1(),
task2(),
task3()
)
# Вывод:
# Task 1 начало
# Task 2 начало
# Task 3 начало
# Task 3 конец (после 0.5 сек)
# Task 2 конец (после 1 сек)
# Task 1 конец (после 2 сек)
# Время выполнения: 2 сек (параллельно!), не 3.5 сек
asyncio.run(main())
Event Loop схема:
┌─────────────────────────────────────┐
│ Event Loop (цикл событий) │
├─────────────────────────────────────┤
│ 1. Выполнить синхронный код │
│ 2. Если встречен await — подвесить │
│ 3. Перейти к следующей корутине │
│ 4. Когда операция завершена — вернуть│
│ 5. Повторить (1-4) │
└─────────────────────────────────────┘
Этап 6: Генераторы (Generators)
Python генераторы как предшественники async/await
# Генератор — функция, которая может приостановиться
def simple_generator():
print("Начало")
yield 1 # Приостановка
print("Возобновление")
yield 2 # Приостановка
print("Конец")
gen = simple_generator()
print(next(gen)) # Начало, затем 1
print(next(gen)) # Возобновление, затем 2
# print(next(gen)) # StopIteration
# Для асинхронности (до async/await)
from collections.abc import Coroutine
def fetch_with_yield():
print("Загружаю данные")
# yield используется для обозначения асинхронной операции
result = yield "loading" # Приостановка
print(f"Получил: {result}")
return result
# Но это сложно для использования, поэтому пришёл async/await
Этап 7: Реактивное программирование (RxJS, ReactiveX)
JavaScript (RxJS)
// Реактивное программирование — потоки данных
import { interval, from } from 'rxjs';
import { map, filter, debounce } from 'rxjs/operators';
// Поток чисел каждые 1000мс
interval(1000)
.pipe(
map(x => x * 2), // Умножить на 2
filter(x => x > 5), // Только больше 5
)
.subscribe(x => console.log(x));
// Поток событий клика
from(document.querySelectorAll('button'))
.pipe(
debounce(500) // Дебаунс каждые 500мс
)
.subscribe(button => console.log('Нажата кнопка'));
Этап 8: Современные подходы (Parallel Processing)
Web Workers (параллелизм в браузере)
// main.js
const worker = new Worker('worker.js');
// Отправить тяжёлое вычисление в отдельный поток
worker.postMessage({ number: 1000000 });
worker.onmessage = (e) => {
console.log('Результат:', e.data);
// Основной поток не был заблокирован!
};
// worker.js
self.onmessage = (e) => {
let sum = 0;
for (let i = 0; i < e.data.number; i++) {
sum += i;
}
self.postMessage(sum);
};
Сравнение подходов
| Подход | Год | Язык | Удобство | Производительность | Читаемость |
|---|---|---|---|---|---|
| Синхронность | - | Все | Простая | Плохая | ✅ Отличная |
| Callbacks | 2000 | JS, Python | ❌ Адский ад | Хорошая | ❌ Плохая |
| Promises | 2015 | JS | 👍 Хорошо | Хорошая | 👍 Хорошая |
| Async/Await | 2017 | JS, Python | ✅ Отличная | Отличная | ✅ Отличная |
| Generators | 2015 | Python | 👍 Средняя | Отличная | 👍 Хорошая |
| RxJS | 2010 | JS | 👍 Средняя | Отличная | 🤔 Сложная |
| Web Workers | 2010 | JS | 👍 Хорошо | ✅ Отличная | 👍 Хорошая |
Практический пример: миграция с кода
// Исходный синхронный код
function loadUserData() {
const user = fetch('/api/user'); // Блокирует!
const posts = fetch(`/api/posts/${user.id}`); // Блокирует!
return { user, posts };
}
// Callback версия
function loadUserData(callback) {
fetch('/api/user', (user) => {
fetch(`/api/posts/${user.id}`, (posts) => {
callback({ user, posts });
});
});
}
// Promise версия
function loadUserData() {
return fetch('/api/user')
.then(user => fetch(`/api/posts/${user.id}`)
.then(posts => ({ user, posts }))
);
}
// Async/Await версия (СОВРЕМЕННЫЙ СТАНДАРТ)
async function loadUserData() {
const user = await fetch('/api/user');
const posts = await fetch(`/api/posts/${user.id}`);
return { user, posts };
}
Производительность: параллельное выполнение
# Синхронный код: 3 запроса по 1 сек = 3 сек
for url in ['api/1', 'api/2', 'api/3']:
result = requests.get(url) # Ждём 1 сек
# Итого: 3 сек
# Асинхронный код: 3 запроса по 1 сек = 1 сек (параллельно)
import asyncio
import aiohttp
async def main():
async with aiohttp.ClientSession() as session:
tasks = [
session.get(url)
for url in ['api/1', 'api/2', 'api/3']
]
results = await asyncio.gather(*tasks)
# Итого: 1 сек (параллельное выполнение)
asyncio.run(main())
Вывод
- Callbacks (2000) → Promises (2015) → Async/Await (2017) — путь совершенствования
- Async/Await — де-факто стандарт в современном программировании
- Event Loop — ключ к пониманию того, как работает асинхронность
- Параллелизм (Web Workers, ThreadPools) — для CPU-bound операций
- Асинхронность — для I/O-bound операций (сеть, файлы, БД)