Конкурентность и параллелизм: важная разница

Два слова, которые путают чаще всего: конкурентность и параллелизм — это не одно и то же.

Конкурентность — это способность системы управлять несколькими задачами, которые продвигаются с перекрытием во времени; параллелизм — это физически одновременное выполнение нескольких задач на разных вычислительных ядрах.

Конкурентность — про структуру: вы разбили программу на независимые задачи, и система чередует их, переключаясь между ними. Параллелизм — про выполнение: задачи реально бегут в одну и ту же физическую миллисекунду на разных ядрах процессора.

Аналогия с поваром

Один повар (одно ядро) готовит три блюда. Пока варится суп, он режет салат, потом переключается на жарку — это конкурентность: одна голова, но несколько дел в работе одновременно по смыслу. Если поставить трёх поваров, каждый делает своё блюдо в один и тот же момент — это параллелизм.

Конкурентность (1 ядро, чередование):
  Задача A:  ##    ##      ##
  Задача B:    ##      ##
  Задача C:        ##      ##
  время  ---------------------->

Параллелизм (3 ядра, одновременно):
  Ядро 1 A:  ##########
  Ядро 2 B:  ##########
  Ядро 3 C:  ##########
  время  ---------------------->

Можно одно без другого

Эти свойства независимы. Бывает:

  • Конкурентность без параллелизма — одно ядро чередует задачи (классическая однопроцессорная многозадачность, как asyncio).
  • Параллелизм без явной конкурентности — например, векторные SIMD-операции над массивом на одном ядре.
  • И то и другое — несколько потоков на нескольких ядрах.

Когда что помогает

Параллелизм ускоряет CPU-bound задачи (тяжёлые вычисления) — больше ядер, быстрее счёт. Конкурентность помогает с I/O-bound задачами (сеть, диск): пока один запрос ждёт ответа, можно заняться другим, и ядер для этого много не нужно.

tasks = ["скачать A", "скачать B", "скачать C"]

# моделируем чередование: каждая задача делает шаг по очереди
for step in range(2):
    for t in tasks:
        print(f"шаг {step}: {t}")

Вывод:

шаг 0: скачать A
шаг 0: скачать B
шаг 0: скачать C
шаг 1: скачать A
шаг 1: скачать B
шаг 1: скачать C

Как работает под капотом

Конкурентность реализуется планировщиком, который чередует задачи: даёт каждой кусочек времени или переключается, когда задача чего-то ждёт. Параллелизм требует физического «железа» — нескольких ядер или процессоров. Поэтому на одноядерной машине вы можете писать конкурентный код, но настоящего параллелизма не получите.

Частые ошибки

  • Считать слова синонимами. Можно быть конкурентным без параллелизма и наоборот.
  • Ждать ускорения вычислений от конкурентности на одном ядре. Чередование не складывает производительность, оно лишь скрывает ожидание.
  • Игнорировать тип нагрузки. Для счёта нужен параллелизм, для ожидания — конкурентность.

Итог

  • Конкурентность — про управление многими задачами (структура).
  • Параллелизм — про одновременное выполнение (железо).
  • I/O-bound выигрывает от конкурентности, CPU-bound — от параллелизма.
  • Свойства независимы и могут сочетаться.
Проверьте себя
1. Чем конкурентность принципиально отличается от параллелизма?
AНичем, это синонимы
BКонкурентность — про управление многими задачами, параллелизм — про одновременное выполнение на разных ядрах
CКонкурентность всегда быстрее
DПараллелизм работает только в asyncio
2. Какой тип нагрузки выигрывает в первую очередь от параллелизма (нескольких ядер)?
AI/O-bound (ожидание сети и диска)
BCPU-bound (тяжёлые вычисления)
CЛюбой ввод с клавиатуры
DТолько вывод в консоль