Что такое планировщик процессов (scheduler)? <!-- grade: middle -->
Планировщик процессов (scheduler) — это компонент ядра ОС, который определяет, какой процесс или поток будет выполняться на каком ядре процессора в каждый момент времени, обеспечивая многозадачность.
Аналогия: планировщик — это диспетчер в аэропорту, который решает, какой самолёт (процесс) получит взлётную полосу (ядро CPU) и на сколько времени. Если самолётов больше, чем полос, они ждут в очереди и взлетают по очереди.
Зачем нужен планировщик
В типичной системе количество запущенных потоков значительно превышает количество ядер CPU. Например, на 8-ядерном процессоре может быть запущено 200+ потоков. Планировщик создаёт иллюзию одновременного выполнения, быстро переключая контекст между потоками.
Основные понятия
- Квант времени (time slice / quantum) — максимальное время непрерывного выполнения процесса на CPU перед принудительным переключением. Обычно 1-10 мс.
- Приоритет — числовое значение, определяющее важность процесса. Процессы с более высоким приоритетом получают больше процессорного времени.
- Вытесняющая многозадачность (preemptive multitasking) — ОС может принудительно забрать CPU у процесса по истечении кванта или при появлении более приоритетного процесса. Используется во всех современных ОС.
Алгоритмы планирования
| Алгоритм | Описание | Достоинства / Недостатки |
|---|---|---|
| Round Robin (RR) | Каждый процесс получает равный квант времени по очереди | Простой и справедливый, но не учитывает приоритеты |
| Priority Scheduling | Процесс с наивысшим приоритетом выполняется первым | Учитывает важность, но возможно голодание (starvation) низкоприоритетных процессов |
| CFS (Completely Fair Scheduler) | Используется в Linux. Выбирает процесс с минимальным «виртуальным временем выполнения». Реализован на красно-чёрном дереве | Справедливый, эффективный, масштабируемый |
| Multilevel Feedback Queue | Несколько очередей с разными приоритетами. Процессы перемещаются между очередями в зависимости от поведения | Адаптивный, но сложен в настройке |
Типы процессов по характеру нагрузки
- CPU-bound — интенсивно используют процессор (вычисления, сжатие, рендеринг). Получают более длинные кванты, чтобы не тратить время на частое переключение контекста.
- I/O-bound — часто ожидают ввода/вывода (сетевые запросы, чтение с диска). Получают более высокий приоритет, так как быстро освобождают CPU и не занимают его подолгу.
Значение для Java-разработчика
Thread.setPriority(int)— подсказка планировщику ОС, но не гарантия. На практике разница между приоритетами потоков Java часто незаметна.- Количество потоков в пуле (
ExecutorService) следует выбирать с учётом характера задач:- Для CPU-bound: ~количество ядер (
Runtime.getRuntime().availableProcessors()). - Для I/O-bound: значительно больше (десятки-сотни), так как потоки большую часть времени ожидают I/O.
- Для CPU-bound: ~количество ядер (
- Виртуальные потоки (Java 21+) имеют собственный планировщик внутри JVM (
ForkJoinPool), но carrier threads по-прежнему планируются ОС. - Чрезмерное количество потоков ОС (тысячи) приводит к деградации из-за частого переключения контекста. Именно эту проблему решают виртуальные потоки.
Вывод
Планировщик ОС распределяет процессорное время между потоками, используя алгоритмы на основе приоритетов и квантов времени. Для Java-разработчика ключевой практический вывод: размер пула потоков зависит от типа задачи — CPU-bound или I/O-bound. Виртуальные потоки Java 21 снимают ограничение на количество одновременных потоков для I/O-bound задач.
На собеседовании: middle-вопрос, часто задаётся в контексте настройки пулов потоков. Покажите, что понимаете разницу между CPU-bound и I/O-bound, и объясните, почему для CPU-bound задач оптимальный размер пула ~ числу ядер. Упоминание CFS и его реализации на красно-чёрном дереве покажет глубокое понимание.