Потоки и процессы (Threads & Processes)
Процесс — запущенная программа со своей памятью, поток — ход выполнения внутри процесса; потоки одного процесса делят общую память.
Процесс и поток — две единицы, из которых операционная система собирает работу программ. Процесс — это запущенная программа со своей памятью и ресурсами. Поток — ход выполнения команд внутри процесса. В каждом процессе есть хотя бы один поток, а часто их десятки.
Что такое процесс
Когда вы запускаете программу, ядро операционной системы создает процесс: выделяет ему участок оперативной памяти, номер (PID), открытые файлы и сетевые соединения. Память процесса изолирована: другой процесс не может ее прочитать или испортить. Поэтому сбой одной программы обычно не роняет остальные.
Что такое поток
Поток (thread) выполняет команды программы. У каждого потока свой стек и свое место в коде, но память, файлы и соединения процесса у всех потоков общие. Создать поток и переключиться между потоками дешевле, чем между процессами: не нужно выделять и защищать отдельную память.
Чем процесс отличается от потока
| Процесс | Поток | |
|---|---|---|
| Память | Своя, изолированная | Общая с другими потоками процесса |
| Создание и переключение | Дороже | Дешевле |
| Обмен данными | Через каналы, сокеты, общую память — средствами ОС | Напрямую через общие переменные |
| Сбой | Обычно не затрагивает другие процессы | Может обрушить весь процесс |
| Пример | Вкладки браузера Chrome работают в отдельных процессах | Веб-сервер обрабатывает запросы пользователей в параллельных потоках |
Зачем программе несколько потоков
- Использовать все ядра. Современный процессор выполняет несколько потоков одновременно, по одному на ядро. Однопоточная программа нагружает лишь одно из них.
- Не ждать. Пока один поток ждет ответа от базы данных или сети, другие продолжают работу.
- Отзывчивый интерфейс. Долгая операция идет в фоновом потоке, и окно приложения не «зависает».
Подробнее об одновременном выполнении задач — в термине «Параллелизм».
Проблемы многопоточности
Общая память удобна, но опасна. Два потока одновременно увеличивают общий счетчик со значения 10: оба прочитали 10, оба записали 11 — одно увеличение потерялось. Это гонка состояний (race condition). Если же поток A захватил ресурс 1 и ждет ресурс 2, а поток B держит ресурс 2 и ждет ресурс 1, оба ждут вечно — это взаимная блокировка (deadlock).
Защищаются блокировками (mutex), атомарными операциями и очередями сообщений, через которые потоки обмениваются данными вместо общих переменных. Такие ошибки проявляются редко и случайно, поэтому их сложно воспроизвести — многопоточный код проверяют особенно тщательно, особенно в системах, где важна каждая операция, например в обработке платежей.
У разных языков свои особенности. В стандартном Python (CPython) из-за глобальной блокировки интерпретатора (GIL) код на Python в каждый момент выполняет только один поток, поэтому для вычислительных задач там чаще запускают несколько процессов.
Как посмотреть процессы и потоки
В Linux процессы показывает ps aux или top, а потоки конкретного процесса — команда:
# Командная строка Linux
top -H -p 1234
где 1234 — номер процесса. О командах для работы с системой — в термине Linux CLI. В Windows те же сведения есть в Диспетчере задач на вкладке «Подробности».