Я запускаю процесс (на ОС Linux 3.x), в котором:
Возможно, что существует избыточная подписка (то есть больше рабочих потоков, чем вдвое больше ядер на процессоре Intel с HT). Теперь я вижу, что потоки «менеджера» не получают процессорного времени достаточно часто. Они не совсем «голодные», я просто хочу дать им толчок. Поэтому, естественно, я думал об установке различных приоритетов потоков (я работаю в Linux), но затем я заметил различные варианты планировщиков потоков и их влияние. В этот момент я запутался, а точнее — мне не понятно
Заметки:
UPD 12.02.2015Я провел несколько экспериментов.
Существует очевидное решение изменить планировщик потоков «менеджер» на RT (планировщик реального времени, который предоставляет политики SCHED_DEADLINE / SCHED_FIFO). В этом случае потоки «менеджера» всегда будут иметь больший приоритет, чем большинство потоков в системе, поэтому они почти всегда получают ЦП, когда им это необходимо.
Тем не менее, есть другое решение, которое позволяет вам оставаться на Планировщик CFS. Ваше описание назначения «рабочих» тем похоже на партия составление расписания (в древние времена, когда компьютеры были большими, пользователь должен поставить свою работу в очередь и часами ждать, пока она не будет выполнена). Linux CFS поддерживает пакетные задания через политику SCHED_BATCH, а задания диалога — через политику SCHED_NORMAL.
Также есть полезный комментарий в коде ядра (ядро / SCHED / fair.c):
/*
* Batch and idle tasks do not preempt non-idle tasks (their preemption
* is driven by the tick):
*/
if (unlikely(p->policy != SCHED_NORMAL) || !sched_feat(WAKEUP_PREEMPTION))
return;
Поэтому, когда «менеджерский» поток или какое-то другое событие пробуждает «рабочий», последний получит ЦП только в том случае, если в системе есть свободные ЦП или когда «менеджер» исчерпает свой временной интервал (чтобы настроить его, измените вес задачи).
Кажется, что ваша проблема не может быть решена без изменения политик планировщика. Если «рабочие» потоки очень заняты, а «менеджер» редко просыпается, они получают то же самое vruntime
бонус, так что «работник» всегда будет вытеснять нити «менеджера» (но вы можете увеличить их вес, чтобы они быстрее исчерпали свой бонус).
У меня есть сервер с двумя процессорами Intel Xeon E5-2420, который дает нам 24 аппаратных потока. Для симуляции двух потоков я использовал свой собственный TSLoad генератор рабочей нагрузки (и исправление нескольких ошибок во время экспериментов :)).
Было два потоковых пула: tp_manager
с 4-мя нитками и tp_worker
с 30 нитями, оба работают busy_wait
рабочие нагрузки (просто for(i = 0; i < N; ++i);
) но с разным количеством циклов цикла. tp_worker
работает в benchmark
режим, поэтому он будет выполнять столько запросов, сколько может и занимает 100% процессорного времени.
Вот пример конфигурации: https://gist.github.com/myaut/ad946e89cb56b0d4acde
3.12 (ваниль с отладочным конфигом)
EXP | MANAGER | WORKER
| sched wait service | sched service
| policy time time | policy time
33 | NORMAL 0.045 2.620 | WAS NOT RUNNING
34 | NORMAL 0.131 4.007 | NORMAL 125.192
35 | NORMAL 0.123 4.007 | BATCH 125.143
36 | NORMAL 0.026 4.007 | BATCH (nice=10) 125.296
37 | NORMAL 0.025 3.978 | BATCH (nice=19) 125.223
38 | FIFO (prio=9) -0.022 3.991 | NORMAL 125.187
39 | core:0:0 0.037 2.929 | !core:0:0 136.719
3.2 (сток Debian)
EXP | MANAGER | WORKER
| sched wait service | sched service
| policy time time | policy time
46 | NORMAL 0.032 2.589 | WAS NOT RUNNING
45 | NORMAL 0.081 4.001 | NORMAL 125.140
47 | NORMAL 0.048 3.998 | BATCH 125.205
50 | NORMAL 0.023 3.994 | BATCH (nice=10) 125.202
48 | NORMAL 0.033 3.996 | BATCH (nice=19) 125.223
42 | FIFO (prio=9) -0.008 4.016 | NORMAL 125.110
39 | core:0:0 0.035 2.930 | !core:0:0 135.990
Некоторые заметки:
nice
может сделать это косвенно) немного сокращает время ожидания.В дополнение к ответу myautt вы также можете привязать менеджер к конкретным процессорам (sched_setaffinity) и рабочие на отдых. Конечно, в зависимости от вашего конкретного случая использования это может быть очень расточительным.
Ссылка на сайт: Поток, привязывающий ядро процессора
Явная уступка обычно не нужна, на самом деле часто не рекомендуется. Процитирую Роберта Лава в «Системном программировании Linux»:
На практике существует несколько законных применений sched_yield () в надлежащей упреждающей многозадачной системе, такой как Linux. Ядро полностью способно принимать оптимальные и наиболее эффективные решения по планированию — конечно, ядро лучше оснащено, чем отдельное приложение, чтобы решить, что выгрузить и когда.
Исключение, о котором он упоминает, — это когда вы ожидаете внешних событий, например, вызванных пользователем, оборудованием или другим процессом. Это не тот случай, в вашем примере.
В дополнение к отличному ответу myaut’а стоит попробовать ядро с примененным набором патчей CONFIG_PREEMPT_RT. Это вносит некоторые довольно серьезные изменения в то, как ядро выполняет планирование, в результате чего задержка планирования становится намного более детерминированной.
Использование в сочетании с получением правильных относительных приоритетов потоков (менеджеры> рабочие) с любым предложением myaut (и особенно с SCHED_FIFO) может дать очень хорошие результаты.