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

«В чем разница в управлении памятью между процессами и потоками?» — вопрос из категории Операционные системы, который задают на 10% собеседований Python Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

Процессы (Processes)

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

  • Изоляция: Сбой в одном процессе (например, ошибка сегментации) не влияет на другие.
  • Ресурсы: У каждого процесса свой набор файловых дескрипторов, стек, куча и сегмент кода.
  • Взаимодействие: Для обмена данными требуется механизм межпроцессного взаимодействия (IPC), например, pipes, queues, shared memory.

Пример: Изменение переменной в дочернем процессе не влияет на родительский.

from multiprocessing import Process

data = [0]

def worker(d):
    d[0] = 99 # Изменяется копия данных в памяти дочернего процесса
    print(f"В дочернем процессе: {d[0]}")

process = Process(target=worker, args=(data,))
process.start()
process.join()

print(f"В родительском процессе: {data[0]}") # Выведет 0

Потоки (Threads)

Все потоки, созданные в рамках одного процесса, разделяют его адресное пространство (кучу, глобальные переменные, сегмент кода).

  • Общая память: Потоки могут напрямую читать и изменять общие данные, что делает взаимодействие быстрым и простым.
  • Собственные ресурсы: У каждого потока есть свой собственный стек (для локальных переменных и вызовов функций) и счетчик команд.
  • Риски: Общий доступ к данным создает риск возникновения состояния гонки (race conditions). Для безопасной работы требуется использовать примитивы синхронизации (Lock, Semaphore и т.д.).

Пример: Изменение переменной в одном потоке видно в другом.

from threading import Thread

data = [0]

def worker(d):
    d[0] = 99 # Изменяется общая для всех потоков переменная
    print(f"В дочернем потоке: {d[0]}")

thread = Thread(target=worker, args=(data,))
thread.start()
thread.join()

print(f"В родительском потоке: {data[0]}") # Выведет 99
Характеристика Процесс Поток
Память Изолированная Общая
Надежность Высокая (изоляция) Низкая (ошибка влияет на всех)
Создание Медленное Быстрое
Взаимодействие Сложное (через IPC) Простое (через общие данные)