Модели вытеснения в Linux
- title
- Модели вытеснения в Linux
- type
- concept
- summary
- PREEMPT_NONE, PREEMPT_FULL и PREEMPT_LAZY - когда ядро вправе отобрать CPU у исполняемого потока
- tags
- linux, kernel, scheduling
- sources
- linux-broke-postgresql
- created
- 2026-04-30
- updated
- 2026-05-14
- lang
- ru
- translation_of
- linux-preemption-models
- source_updated
- 2026-05-14
- translated
- 2026-09-01
- translator
- lllm/antigravity/gemini-3.7-flash-medium
Вытеснение (preemption) - это решение планировщика о том, когда ему разрешено прервать работающий поток и передать CPU другому. Разным нагрузкам подходят разные ответы, поэтому ядро Linux предлагает этот выбор в виде конфигурации времени сборки.
Три модели
PREEMPT_NONE - ядро почти никогда не прерывает исполняемый поток. Тот работает, пока сам не отдаст CPU: системный вызов, блокирующий I/O, явный sleep. Минимум переключений контекста, высокая пропускная способность, предсказуемое поведение под нагрузкой. Традиционный выбор по умолчанию для серверов.
PREEMPT_FULL - ядро может прервать работающий поток практически в любой безопасной точке, включая выполнение внутри самого ядра. Ниже задержки, выше накладные расходы на переключение контекста. Традиционный выбор по умолчанию для десктопов, где отзывчивость важнее пропускной способности.
PREEMPT_LAZY - компромиссный вариант, появившийся в Linux 6.12. Вытеснение разрешено, но планировщик старается дождаться естественных границ, прежде чем вмешиваться. Задумывался как прямая замена PREEMPT_NONE для нагрузок, требующих высокой пропускной способности.
Что изменилось в Linux 7.0
В Linux 7.0 убрали PREEMPT_NONE для современных процессорных архитектур, оставив PREEMPT_FULL и PREEMPT_LAZY. Большинство серверных дистрибутивов переключили своё значение по умолчанию на PREEMPT_LAZY. Для подавляющего большинства программ переход прошёл незаметно. Но там, где он заметен, последствия оказались серьёзными - см. linux-7-postgres-regression с примером нагрузки (PostgreSQL на машине с 96 vCPU), где изменение уронило пропускную способность вдвое: теперь планировщик может вытеснить поток, удерживающий spinlock прямо во время обработки page fault.
Почему "drop-in" на деле не drop-in
PREEMPT_NONE давал неявную и бесплатную гарантию для любого кода, удерживающего spinlock: даже если владелец блокировки делал что-то требующее обработки ядром (page fault, slow path), его не вытесняли до завершения работы. Код, написанный до PREEMPT_LAZY, мог негласно на это полагаться. С удалением этого режима любое предположение в духе "владелец освободит блокировку за наносекунды" обязано строго соблюдаться на практике - либо подкрепляться чем-то более надёжным, вроде restartable sequences.
Что происходит до того, как всё это приобретает значение
Модель вытеснения вступает в силу только после завершения загрузки. На фазе 4 в linux-kernel-startup (start_kernel) прерывания отключены почти всё время, а планировщик хоть и существует, но ещё не балансирует нагрузку. Настоящая многозадачность - мир, где решения о вытеснении действительно имеют значение, - начинается на фазе 6 с вызова sched_init_smp(). Общий порядок описан в linux-boot-phases.