Как планировщик ОС решает, какой поток выполнять?
- Что такое вытесняющая многозадачность?
- Чем CPU-bound задача отличается от I/O-bound?
- Что такое load average?
Планировщик выдаёт потокам, готовым к работе, кванты времени на ядрах и вытесняет их по таймеру — так один поток не захватит процессор.
- Ждущие ввода-вывода потоки не занимают процессор — они спят в очереди ожидания
- В Linux — CFS/EEVDF: честно делит время с учётом nice-приоритета
- I/O-bound задачи большую часть времени ждут, CPU-bound — считают
А ещё Load average — средняя длина очереди готовых и ждущих диска потоков, сравнивать с числом ядер
Подробно
Состояния потока: выполняется (на ядре), готов (ждёт своей очереди на процессор), ждёт (ввода-вывода, блокировки, таймера). Планировщик работает с готовыми.
Вытесняющая многозадачность. Таймер периодически прерывает выполнение, и ядро решает, оставить текущий поток или переключиться. Поток также уступает процессор сам, когда блокируется. Кооперативная многозадачность, где задача отдаёт управление только сама, осталась в пользовательских планировщиках — event loop в asyncio и Node.js: одна задача с бесконечным циклом без await повесит всё.
Linux. Долгое время работал CFS — «совершенно честный планировщик»: каждому потоку учитывается виртуальное время выполнения, и следующим идёт тот, кто получил меньше всего (структура — красно-чёрное дерево). С версии 6.6 его заменил EEVDF, сохранив идею честного деления. Приоритет задаётся nice от −20 до 19 — это вес при делении, а не жёсткий порядок. Для задач реального времени есть отдельные политики (SCHED_FIFO).
CPU-bound и I/O-bound. Вычислительная задача использует весь квант, и потоков больше, чем ядер, ей не нужно. Задача ввода-вывода почти всё время ждёт, поэтому потоков может быть больше ядер — или вообще один поток с event loop. Для пулов это даёт оценку: число потоков ≈ ядра × (1 + время ожидания / время вычисления).
Load average в uptime и top — экспоненциальные средние за 1, 5 и 15 минут числа потоков, которые выполняются или готовы выполняться (в Linux ещё и ждущие диска в состоянии D). Значение 8 на 8 ядрах — полная загрузка, 30 на 8 ядрах — очередь, задержки растут. Высокий load average при низкой загрузке CPU указывает на ожидание диска.
Контейнеры. Лимит CPU в Kubernetes реализован квотой CFS: при превышении квоты потоки замораживаются до следующего периода (throttling) — отсюда скачки задержки при «свободном» процессоре.
Пример
$ uptime
10:21:04 up 12 days, load average: 15.82, 14.10, 9.37
$ nproc
8
# Очередь вдвое длиннее числа ядер и растёт — запросы ждут процессор.
$ nice -n 10 ./batch-report # фоновая задача получит меньшую долю CPUЧто хотят услышать
- Состояния потока и что планирует планировщик.
- Вытеснение по таймеру и добровольная уступка при ожидании.
- Разница CPU-bound и I/O-bound и вывод для размера пулов.
- Load average и сравнение с числом ядер.
- Throttling в контейнерах — плюс.
Частые ошибки
- Считать load average процентом загрузки CPU.
- Думать, что nice даёт жёсткий порядок выполнения.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✓Выдаёт готовым потокам кванты и вытесняет по таймеру; ждущие не занимают CPU
- ✗Поток работает, пока сам не отдаст процессор
- ✗Потоки, ожидающие диска, постоянно занимают ядро
- ✗Load average — процент загрузки одного ядра
Что спросят дальше
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.