Встречается на 33% собеседований по Go

В чем разница процесса и потока в рамках операционной системы

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

Как это работает

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

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

Основные различия

КритерийПроцессПоток
ИзоляцияПолная изоляция памяти и ресурсовОбщая память и ресурсы внутри процесса
ПамятьСобственное адресное пространствоОбщее адресное пространство процесса
СозданиеРесурсоемкоЛегковесно
ВзаимодействиеТолько через IPC (сокеты, очереди, разделяемая память)Напрямую через общую память
НадежностьСбой одного процесса не влияет на другиеСбой потока может уронить весь процесс
СинхронизацияНе требуется для изоляцииТребуется для доступа к общим данным (мьютексы, каналы)

Пример на Go

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

go
package main

import (
    "fmt"
    "os/exec"
    "sync"
)

func main() {
    // Создание процесса: запускаем внешнюю команду
    cmd := exec.Command("echo", "hello from process")
    out, _ := cmd.Output()
    fmt.Println(string(out))

    // Создание потока: используем горутину (планируется на потоке ОС)
    var wg sync.WaitGroup
    wg.Add(1)
    go func() {
        defer wg.Done()
        fmt.Println("hello from goroutine")
    }()
    wg.Wait()
}

Здесь exec.Command создает отдельный процесс, а горутина выполняется в потоке текущего процесса. Горутины дешевле потоков ОС, но концептуально аналогичны: они разделяют память процесса.

Подводные камни

  • Гонки данных: из-за общей памяти потоки требуют синхронизации. Используйте мьютексы или атомарные операции.
  • Взаимные блокировки: неправильный порядок блокировок может привести к deadlock.
  • Утечки ресурсов: потоки и процессы нужно корректно завершать, иначе система исчерпает ресурсы.
  • Стоимость переключения: хотя потоки легче, их слишком много может снизить производительность из-за частых переключений.

Когда использовать

  • Процессы — когда нужна строгая изоляция и безопасность: веб-серверы, обрабатывающие запросы в отдельных процессах, микросервисы, приложения, где сбой не должен затрагивать другие компоненты.
  • Потоки — когда важна производительность и параллельная обработка данных: видеоредакторы, научные вычисления, серверы с большим количеством одновременных соединений (при использовании потоков ОС).

Коротко

  • Процесс — изолированный экземпляр программы со своей памятью; поток — легковесная единица внутри процесса, разделяющая память.
  • Создание и переключение процессов дороже, чем потоков.
  • Взаимодействие между процессами требует IPC, между потоками — общая память и синхронизация.
  • Выбор зависит от требований к изоляции, производительности и сложности синхронизации.
как отвечать на вопрос
пример собеседования
фреймворки на собеседовании
типичные вопросы junior
интервью вопросы и ответы