---
title: Многопоточность и многопроцессорность
questionDates:
  q-transfer-0241: '2026-10-01'
  q-transfer-0273: '2026-10-01'
  q-transfer-0274: '2026-10-01'
seo:
  description: >-
    Тема «Многопоточность и многопроцессорность» для собеседования Python
    Developer. Что такое GIL (Global Interpreter Lock)? В чем отличие
    multiprocessing от multithreading в Python?
  title: Многопоточность и многопроцессорность — Python Developer
---

[Все темы Python Developer](/prep/python-developer)

## <strong>Что такое GIL (Global Interpreter Lock)?</strong> [#q-14bee738d69b816993dbdd9ed13f5b08]

GIL в обычной сборке CPython допускает выполнение байт-кода только одним потоком за раз в одном интерпретаторе. При блокирующем вводе-выводе и в некоторых расширениях на C он освобождается. Это ограничивает параллелизм вычислений на Python, но не исключает полезную многопоточность. Начиная с CPython 3.13 доступны отдельные free-threaded сборки без GIL.

:::note[Ссылки для изучения]

1. [Зачем нужен GIL и каково его влияние на многопоточность](https://habr.com/ru/articles/592189/)
   :::

---

## <strong>В чем отличие multiprocessing от multithreading в Python?</strong> [#q-14bee738d69b81c88874d7bbd9d8eae2]

Отличие между <code>multiprocessing</code> и <code>multithreading</code> в Python заключается в том, как они обрабатывают параллелизм&#58;

#### <strong>Multiprocessing</strong>&#58;

- <code>multiprocessing</code> позволяет создавать отдельные процессы для
  выполнения задач.

- Каждый процесс имеет свое собственное пространство памяти, что делает его более надежным при работе с разделяемой памятью и предотвращает проблемы с GIL.

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

#### <strong>Multithreading</strong>&#58;

- <code>multithreading</code> создает несколько потоков внутри одного процесса
  для выполнения задач.

- Потоки разделяют общее пространство памяти процесса, что может привести к проблемам с синхронизацией доступа к общим ресурсам.

- Это подходит для задач с большим количеством ввода-вывода (I/O-bound), так как потоки могут блокироваться при ожидании завершения операций ввода-вывода.

В целом, <code>multiprocessing</code> обеспечивает большую изоляцию и параллелизм, в то время как <code>multithreading</code> может быть эффективным для задач, требующих ввода-вывода, но может столкнуться с проблемами с синхронизацией при доступе к общим ресурсам.

:::note[Ссылки для изучения]

1. [Зачем нужен GIL и каково его влияние на многопоточность](https://habr.com/ru/articles/592189/)
2. [Асинхронность, потоки и процессы. Артём Шумейко, с 0:02](https://www.youtube.com/watch?v=ao1rb4mqLZQ&t=2s)

:::

---

## <strong>Каковы различия между IO-bound и CPU-bound задачами?</strong> [#q-14bee738d69b81be8503f1ee2d07a799]

Различия между IO-bound и CPU-bound задачами связаны с тем, какие ресурсы больше всего использует каждая из них&#58;

#### <strong>IO-bound задачи</strong>&#58;

- Эти задачи в основном зависят от операций ввода-вывода (IO), таких как чтение и запись файлов, сетевые запросы и т. д.

- Примеры IO-bound задач включают загрузку веб-страниц, чтение больших файлов, обращение к базам данных и т. д.

- В таких задачах основное время ожидания затрачивается на ожидание завершения операций ввода-вывода, а не на обработку данных.

#### <strong>CPU-bound задачи</strong>&#58;

- Эти задачи требуют большого количества вычислительных ресурсов процессора (CPU).

- Примеры CPU-bound задач включают математические вычисления, обработку данных, компиляцию программ и т. д.

- В таких задачах основное время затрачивается на обработку данных или выполнение алгоритмов, а не на ожидание операций ввода-вывода.

:::note[Ссылки для изучения]

1. [Зачем нужен GIL и каково его влияние на многопоточность](https://habr.com/ru/articles/592189/)
2. [IO-bound и CPU-bound работа. Артём Шумейко, с 0:20](https://www.youtube.com/watch?v=ao1rb4mqLZQ&t=20s)

:::

---

## Где лучше использовать потоки и асинхронность в Python? [#q-14bee738d69b813c986fc351745551bb]

<span id="q-14bee738d69b81b6b349e970c94ff49c"></span>

Потоки подходят для конкурентного выполнения блокирующего ввода-вывода, особенно если библиотеки имеют синхронный API. В обычной сборке CPython GIL мешает потокам параллельно выполнять CPU-bound код на Python, поэтому для тяжёлых вычислений чаще используют процессы. Исключения: расширения, которые освобождают GIL, и free-threaded сборки Python.

`asyncio` удобно для большого числа одновременно ожидающих операций, если весь стек поддерживает неблокирующий async API. Оно работает в одном потоке, переключая корутины в точках `await`, поэтому блокирующий вызов внутри event loop останавливает остальные задачи.

Подробнее: [потоки](https://docs.python.org/3/library/threading.html) и [`asyncio`](https://docs.python.org/3/library/asyncio.html) в документации Python.

:::note[Ссылки для изучения]

1. [Блокирующий I/O внутри корутины и перенос через to_thread — русский справочник asyncio](https://asyncio.ru/3.15/library/asyncio-task.html#running-in-threads)
2. [Потоки и асинхронность для IO-bound задач. Артём Шумейко, с 0:20](https://www.youtube.com/watch?v=ao1rb4mqLZQ&t=20s)

:::

---

## Почему GIL не устраняет гонки данных? [#q-transfer-0241]

GIL в обычной сборке CPython разрешает исполнять Python bytecode одному потоку за раз, но составная операция состоит из нескольких шагов, между которыми возможно переключение; C-расширение также может отпустить GIL. Поэтому read-modify-write общего объекта остается гонкой. Критическую секцию защищают Lock или убирают совместное изменяемое состояние. Free-threaded CPython делает зависимость от GIL еще менее допустимой. Корректность проверяют под конкуренцией и при завершении процесса, потому что последовательный тест не обнаруживает гонку.

:::note[Ссылки для изучения]

1. [Почему GIL не защищает составные обновления: гонка read–modify–write — разбор CPython 3.9](https://habr.com/ru/companies/wunderfund/articles/586360/)
   :::

---

## Как процессам безопасно разделять данные? [#q-transfer-0273]

Процессы имеют раздельную память. Небольшие сообщения безопаснее передавать через `multiprocessing.Queue` или pipe с ценой сериализации. Для больших буферов подходит shared memory, а `Value` и `Array` дают простые разделяемые значения; доступ к составному состоянию синхронизируют Lock или Semaphore. `Manager` удобен, но прокси и отдельный server process дороже. Владелец и жизненный цикл shared segment должны быть явными. Корректность проверяют под конкуренцией и при завершении процесса, потому что последовательный тест не обнаруживает гонку.

:::note[Ссылки для изучения]

1. [Обмен данными между процессами и жизненный цикл shared memory — опыт Авито](https://habr.com/ru/companies/avito/articles/866338/)
   :::

---

## Как выбрать примитив синхронизации потоков? [#q-transfer-0274]

`Lock` защищает одну критическую секцию, `RLock` допускает повторный вход того же потока, `Semaphore` ограничивает число одновременных владельцев ресурса. `Event` сообщает факт наступления состояния, а `Condition` позволяет ждать предикат под общей блокировкой и перепроверять его в цикле. Примитив выбирают из протокола взаимодействия. Он не исправляет слишком крупную общую mutable-state модель и может добавить дедлоки. Корректность проверяют под конкуренцией и при завершении процесса, потому что последовательный тест не обнаруживает гонку.

:::note[Ссылки для изучения]

1. [Lock, RLock, Condition, Semaphore и Event: различия примитивов threading — русский справочник Python](https://asyncio.ru/3.15/library/threading.html#lock-objects)
   :::
