Получить доступ

Что такое переключение контекста и почему оно дорогое?

MiddleОперационные системы
Ещё спрашивают так:
  • Почему тысяча потоков работает медленнее, чем восемь?
  • Сколько стоит переключение между потоками?
Коротко

Ядро останавливает один поток, сохраняет его регистры и состояние и загружает другой. Прямая цена — единицы микросекунд, но главное — остывшие кэши процессора.

  • Между процессами дороже: меняется адресное пространство, сбрасывается TLB
  • Причины: истёк квант времени, поток ушёл ждать ввода-вывода или блокировки
  • Потоков больше, чем ядер, — больше переключений и меньше полезной работы

А ещё Отсюда пулы потоков, event loop и виртуальные потоки

Так подсказку видит пользователь sotto на живом собеседовании — за пару секунд, пока вы думаете вслух.

Подробно

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

Когда переключаются:

  • вытеснение — поток израсходовал квант времени (единицы миллисекунд), или проснулся поток с более высоким приоритетом;
  • добровольно — поток ушёл ждать: чтение с диска или из сети, захват занятого мьютекса, sleep, ожидание условия.

Из чего цена:

  • прямая — вход в ядро, сохранение и восстановление регистров, работа планировщика. Порядок единиц микросекунд;
  • косвенная — новый поток работает с другими данными, кэши L1/L2 и предсказатель переходов заполнены чужим. Первое время он работает медленно, пока кэши не прогреются. Это часто дороже прямой части;
  • между процессами — ещё и смена таблиц страниц, сброс TLB (кэша трансляции адресов).

Практические следствия:

  • для вычислений потоков больше, чем ядер, не нужно — они только мешают друг другу;
  • для ввода-вывода раньше заводили поток на соединение, и при десятках тысяч соединений система тратила время на переключения и память на стеки. Отсюда неблокирующий ввод-вывод и event loop (nginx, Node.js, asyncio), а в Java 21 — виртуальные потоки: переключение между ними делает JVM в пользовательском пространстве, без ядра;
  • захват спорной блокировки — это тоже переключение: поток засыпает и просыпается. Поэтому короткие критические секции и спин-блокировки на короткое ожидание.

Посмотреть число переключений: vmstat 1 (колонка cs), pidstat -w.

Пример

vmstat 1
procs ---------memory-------- ---system-- ------cpu-----
 r  b   swpd   free   ...       in    cs   us sy id wa
32  0      0  812344  ...     9100 185000  41 38 21  0

Сотни тысяч переключений в секунду и высокий sy (время в ядре) — признак того, что потоков слишком много или они дерутся за блокировку.

Что хотят услышать

  • Что сохраняется и восстанавливается.
  • Две причины: вытеснение и ожидание.
  • Косвенная цена через кэши, а не только прямая.
  • Вывод: число потоков под задачу, пулы, event loop, виртуальные потоки.

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

  • «Больше потоков — быстрее» для вычислительной задачи.
  • Считать, что переключение между потоками и процессами стоит одинаково.

Что спросят дальше

Связанные вопросы

Закрытая бета

Подсказки на собеседовании — в реальном времени

sotto слышит вопрос интервьюера и показывает короткий ответ и план, как в блоке «Коротко». Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем