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

В чём разница между асинхронностью и параллельности?

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

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

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

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

Разница между асинхронностью и параллельностью

Это два разных подхода к управлению множественными задачами, часто путаемые между собой. Главное отличие: параллельность - это физическая одновременность, асинхронность - это логическая одновременность.

Визуальное объяснение

Синхронный код (линейный):

Время:  1-----2-----3-----4-----5-----6
Задача: A=====A====B=====B====C=====C

Ожидание: сначала заканчивается A, потом начинается B

Параллельность (несколько потоков/процессов):

Поток 1: 1-----2-----3
Поток 2: 1-----2-----3
Процесс: A======A     (в момент времени 1-3)
         B======B     (в момент времени 1-3)
Действительно одновременно!

Асинхронность (один поток, event loop):

Эвент лооп: 1-----2-----3-----4-----5-----6
Процесс:    A..B..A..B..A..B..
            (чередуются, но не одновременно)
А ждет на I/O → B может выполниться

Параллельность (Parallelism)

Это настоящее одновременное выполнение кода несколькими CPU ядрами или процессами.

import multiprocessing
import time

def cpu_bound_task(n):
    """Вычислительно интенсивная операция"""
    total = 0
    for i in range(n):
        total += i
    return total

# Последовательное выполнение (медленно)
start = time.time()
result1 = cpu_bound_task(100_000_000)
result2 = cpu_bound_task(100_000_000)
print(f"Последовательно: {time.time() - start:.2f}с")
# Вывод: Последовательно: 10.45с

# Параллельное выполнение (быстро на многоядерной системе)
start = time.time()
with multiprocessing.Pool(2) as pool:
    results = pool.map(cpu_bound_task, [100_000_000, 100_000_000])
print(f"Параллельно: {time.time() - start:.2f}с")
# Вывод: Параллельно: 5.23с

Характеристики параллельности:

  • Несколько CPU ядер работают одновременно
  • Каждый процесс имеет свой интерпретатор Python и памяти
  • Нет GIL (Global Interpreter Lock)
  • Высокий overhead на создание процессов
  • Подходит для CPU-bound задач

Асинхронность (Asynchrony)

Это когда одна программа (один поток) переключается между несколькими задачами, когда одна ждет (например, I/O).

import asyncio
import aiohttp
import time

async def fetch_url(session, url):
    """Асинхронный запрос"""
    async with session.get(url) as response:
        return await response.text()

async def fetch_all_async():
    urls = [
        https://api.github.com/users/github,
        https://api.github.com/users/google,
        https://api.github.com/users/microsoft,
    ]
    
    async with aiohttp.ClientSession() as session:
        tasks = [fetch_url(session, url) for url in urls]
        results = await asyncio.gather(*tasks)
        return results

# Асинхронное выполнение (быстро - НЕ ждет каждый запрос)
start = time.time()
results = asyncio.run(fetch_all_async())
print(f"Асинхронно: {time.time() - start:.2f}с")
# Вывод: Асинхронно: 1.5с (все 3 запроса параллельно)

Как это работает внутри:

async def main():
    print("Начало 1")
    await asyncio.sleep(1)  # I/O операция
    print("Конец 1")
    
    print("Начало 2")
    await asyncio.sleep(1)  # I/O операция
    print("Конец 2")

asyncio.run(main())
# Начало 1
# Начало 2          <- Переключился на вторую задачу пока первая ждет
# Конец 1           <- Первая задача готова
# Конец 2
# Общее время: ~2 сек (а не 4, как в синхронном коде)

Характеристики асинхронности:

  • Один поток, один процесс
  • Event loop управляет переключением между задачами
  • GIL не проблема (одна задача работает за раз)
  • Очень малый overhead
  • Подходит для I/O-bound задач
  • Требует async/await синтаксиса

Многопоточность (Threading)

Средний вариант между параллельностью и асинхронностью:

import threading
import requests
import time
from concurrent.futures import ThreadPoolExecutor

def fetch_url_sync(url):
    """Синхронный запрос"""
    response = requests.get(url)
    return response.status_code

def fetch_all_threading():
    urls = [
        https://api.github.com/users/github,
        https://api.github.com/users/google,
        https://api.github.com/users/microsoft,
    ]
    
    with ThreadPoolExecutor(max_workers=3) as executor:
        results = list(executor.map(fetch_url_sync, urls))
        return results

# Многопоточное выполнение
start = time.time()
results = fetch_all_threading()
print(f"Многопоточно: {time.time() - start:.2f}с")
# Вывод: Многопоточно: 1.5с

Характеристики многопоточности:

  • Несколько потоков в одном процессе
  • GIL ограничивает истинный параллелизм CPU
  • Может обмениваться памятью между потоками
  • Более высокий overhead, чем asyncio
  • Хороша для I/O-bound, но не для CPU-bound
  • Проще в использовании, чем asyncio

Сравнительная таблица

ХарактеристикаСинхронный кодМногопоточностьАсинхронностьПараллельность
Одновременное выполнениеНетЛогическоеЛогическоеФизическое
CPU ядра111Несколько
GIL проблема-ДаНетНет
Для I/O-boundМедленноБыстроОчень быстроБыстро
Для CPU-boundНормальноМедленноМедленноОчень быстро
ComplexityНизкаяСредняяСредняяВысокая
Overhead памятиМинимумСреднийМинимумВысокий
Пример использованияCRUD операцииWeb скрейпингМикросервисыОбработка больших данных

Практические примеры

3 задачи, 3 секунды каждая (I/O):

Синхронный:      ▓▓▓▓▓▓ = 9 сек
Многопоточность: ▓░░░▓░░░▓░░░ = ~3 сек
Асинхронность:   ▓░░░▓░░░▓░░░ = ~3 сек
Параллельность:  ▓░░░▓░░░▓░░░ = ~3 сек

3 задачи, 3 сек CPU работа:

Синхронный:      ▓▓▓▓▓▓ = 9 сек
Многопоточность: ▓░▓░▓░▓░ = ~9 сек (GIL!)
Асинхронность:   ▓░▓░▓░▓░ = ~9 сек
Параллельность:  ▓▓▓ = ~3 сек (на 3-ядерном CPU)

Как выбрать

  1. I/O-bound операции (сеть, диск, БД) → asyncio (лучше всех)
  2. Много I/O операций → asyncio
  3. Чистые вычисления → multiprocessing
  4. Простой код, средние нагрузки → threading
  5. Очень простая задача → синхронный код

Важные замечания

  • asyncio требует, чтобы библиотеки поддерживали async (aiohttp, asyncpg)
  • threading может использовать обычные библиотеки (requests, psycopg2)
  • Комбинируй подходы: asyncio + multiprocessing для гибридных нагрузок
  • Не путай: concurrent != parallel
В чём разница между асинхронностью и параллельности? | PrepBro