Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
 Многопоточность - исследование длительности квантов времени  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1112
Многопоточность - исследование длительности квантов времени

В развлекательных целях разработал программу для измерения длительности квантов времени. В программе необходимо указать количество запускаемых потоков, а в диспетчере задач выполнить привязку процесса к одному ядру. Затем нажать кнопку "Запустить потоки на 5 секунд".

Код метода TCalcQuantThread.Execute:
procedure TCalcQuantThread.Execute;
var
  StartTicks, BreakDiff, QuantDiff, CurQuantTime: Int64;
  PrevTicks, CurTicks, CurQuantStart: Int64;
  Freq: Int64;
begin
  QueryPerformanceFrequency(Freq);
  QueryPerformanceCounter(StartTicks);
  PrevTicks := StartTicks;
  CurQuantStart := StartTicks;
  BreakDiff := 5 * Freq;
  QuantDiff := Round(0.001 * Freq);
  CurQuantTime := 0;
  repeat
    QueryPerformanceCounter(CurTicks);
    Inc(LoopCount);
    if CurTicks - PrevTicks > QuantDiff then
    begin // Если разница оказалась больше 1 мс, значит ОС приостанавливала
          // работу потока и теперь начался отсчёт нового кванта
      AddToWorkList(CurQuantTime / Freq); // Сохраняем время работы потока
      AddToNotWorkList((CurTicks - PrevTicks) / Freq); // Сохраняем время простоя потока
      CurQuantStart := CurTicks;
      CurQuantTime := 0;
    end else
      CurQuantTime := CurTicks - CurQuantStart;
    PrevTicks := CurTicks;
  until (CurTicks - StartTicks) > BreakDiff;
  if CurQuantTime > 0 then // Обрабатываем длительность последнего кванта
    AddToWorkList(CurQuantTime / Freq);
  IsFinish := True;
end;


Ссылка на архив с программой (исходники + исполняемый файл):


Вот такие выводы у меня получились:
1) привязка потока к ядру процессора не является постоянной. Это хорошо видно, если запустить только один поток и не привязывать его к ядру в диспетчере задач. При этом часто оказываются загружены несколько ядер (суммарная загрузка не более 100%).
2) ОС старается распределить загрузку по всем доступным ядрам. Если запущены 4 вычислительных потока, то ОС распределит нагрузку по 4-м ядрам (у меня 4-ядерный процессор без гипертрединга).
3) если за одном ядре запущен только один такой поток (вычислительный), то определить длительность кванта времени не удаётся. Предполагаю, что поток отработал свой квант (предположим 50 мс), затем ОС его усыпила, но поскольку нет других потоков, которым нужен процессор, ОС тут же его пробуждает.
4) квант времени - не такая уж маленькая величина. Типичная длительность кванта времена на моём ноутбуке с Intel Core i3 (поколение не знаю) составляет 95мс. Подчеркну - именно для потоков, выполняющих тяжёлые вычислительные задачи (т.е. грузят процессор на 100% и сами по своей воле не засыпают).
5) если запускать потоки с максимальным приоритетом на одном ядре, то происходит их последовательное выполнение. Т.е. если мы создадим 10 потоков с максимальным приоритетом на одном ядре, то будем ждать их завершения 50 сек (примерно так, но тут я недостаточно исследовал :)
6) с помощью функции GetTickCount невозможно решить данную задачу (пытался с ней вначале), т.к. она начинает возвращать новое значение лишь спустя 16 мс. Такая у неё разрешающая способность. А у функции QueryPerformanceCounter точность гораздо выше: менее 1 микросекунды.


Разработанный пример может оказаться полезен начинающим программистам, изучающим тему многопоточности.
Особенности программы следующие:
1) За уничтожение объекта потока отвечает форма TForm1. Объект потока не уничтожается автоматически при завершении работы метода Execute. При завершении работы потока выставляется поле "IsFinish := True", которое анализируется в событии таймера "TForm1.Timer1Timer".
2) Программа может создать любое количество потоков, которое укажет пользователь (в разумных пределах). Каждому потоку назначается порядковый номер, который передаётся при создании объекта потока с помощью конструктора "TCalcQuantThread.Create"
3) Для хранения ссылок на созданные объекты потоков используется список FList: TList.
4) При срабатывании таймера осужествляется обход списка FList в обратном порядке и для всех потоков, у которых выставлено IsFinish=True, осуществляется вывод собранной информации в компонент Memo1: TMemo, после чего объект потока уничтожается (T.Free), а соответствующий ему элемент удаляется из списка FList.
5) В том случае, если пользователь решил закрыть программу раньше, чем окончатся 5 секунд, в событии TForm1.FormDestroy произойдёт обход списка FList и для каждого объекта потока последовательно будет вызван метод Free. Посколько все потоки выполняются 5 секунд и заканчиваются почти в одно время, то вызов метода Free займет время только для самого первого элемента списка FList. Остальные вызовы Free выполнятся моментально, т.к. к этому времени все потоки уже завершат свою работу.
4 июн 20, 19:56    [22145900]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточность - исследование длительности квантов времени  [new]
shalamyansky
Member

Откуда:
Сообщений: 156
Приятное исследование, спасибо.
DmSer

6) с помощью функции GetTickCount невозможно решить данную задачу (пытался с ней вначале), т.к. она начинает возвращать новое значение лишь спустя 16 мс. Такая у неё разрешающая способность.

См. SetSystemTimeAdjustment
Это разрешение можно задавать, начиная со 100 нс. Вроде бы. Так написано, можете попробовать.
4 июн 20, 21:44    [22145930]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточность - исследование длительности квантов времени  [new]
wadman
Member

Откуда: Санкт-Петербург
Сообщений: 26656
DmSer
она начинает возвращать новое значение лишь спустя 16 мс.

Это если не ставить на десятке красивые анимационные темы и не запускать вижуал студии.
Майкросовтские (и не только) поделия играют этим показателем как им хочется.

Эксперимент показал, что сферический конь в вакууме ведет себя всегда одинаково.

ЗЫ. Я тоже этим игрался, когда мне нужна была быстрая реакция при общении с чувствительной железкой.
4 июн 20, 22:10    [22145945]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточность - исследование длительности квантов времени  [new]
s62
Member

Откуда: Жуковский
Сообщений: 1127
DmSer,

на сайте MS пишут, что промежуток времени, который выделяется потоку (time slice) - примерно 20 мс.
https://docs.microsoft.com/en-us/windows/win32/procthread/multitasking

Сообщение было отредактировано: 4 июн 20, 22:14
4 июн 20, 22:15    [22145951]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточность - исследование длительности квантов времени  [new]
misha mike
Member

Откуда:
Сообщений: 710
DmSer, все это можно было прочитать в книге Руссиновича и без экспериментов :)
4 июн 20, 22:19    [22145956]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточность - исследование длительности квантов времени  [new]
Kazantsev Alexey
Member

Откуда:
Сообщений: 4469
shalamyansky
См. SetSystemTimeAdjustment
Это разрешение можно задавать, начиная со 100 нс. Вроде бы. Так написано, можете попробовать.

Эта функция совсем для других целей. Чтобы изменить точность GetTickCount нужно использовать функцию timeBeginPeriod.
4 июн 20, 22:19    [22145957]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточность - исследование длительности квантов времени  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1112
s62
DmSer,

на сайте MS пишут, что промежуток времени, который выделяется потоку (time slice) - примерно 20 мс


Я тоже ожидал примерно такого значения. А по факту чаще 95 мс наблюдаю :)
4 июн 20, 22:24    [22145963]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточность - исследование длительности квантов времени  [new]
Barmaley57
Member

Откуда: Москва
Сообщений: 5745
Гы))
4 июн 20, 22:26    [22145967]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточность - исследование длительности квантов времени  [new]
misha mike
Member

Откуда:
Сообщений: 710
DmSer, в догонку. Безобидная на первый взгляд функция timeSetEvent (создание мультимедийного таймера) вторым параметром принимает точность таймера в миллисекундах. Так вот, это значение, как оказалось, становится длительностью кванта глобально для всей системы пока работает этот таймер.

P.S. Хех, опоздал...

Сообщение было отредактировано: 4 июн 20, 22:27
4 июн 20, 22:27    [22145968]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточность - исследование длительности квантов времени  [new]
Kazantsev Alexey
Member

Откуда:
Сообщений: 4469
Barmaley57,

Кстати, ты там про QIP писал. Он мог не сам менять точность, а просто использовать компонент, который меняет, TVirtualTreeView, например ;)
4 июн 20, 22:35    [22145974]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточность - исследование длительности квантов времени  [new]
defecator
Member

Откуда:
Сообщений: 39208
Kazantsev Alexey
Barmaley57,

Кстати, ты там про QIP писал. Он мог не сам менять точность, а просто использовать компонент, который меняет, TVirtualTreeView, например ;)


про QIP и я писал лет более 10-ти назад, что он размер кванта меняет.
4 июн 20, 23:01    [22145990]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточность - исследование длительности квантов времени  [new]
Barmaley57
Member

Откуда: Москва
Сообщений: 5745
Я QIP случайно идентифицировал, как виновника, когда разбирался с "поехавшим" планированием потоков. Тогда меня этот прикол сильно удивил. Из-за одного приложения меняются механизмы планирования во всей системе! Мелкософты - они такие))
4 июн 20, 23:31    [22146004]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточность - исследование длительности квантов времени  [new]
misha mike
Member

Откуда:
Сообщений: 710
Barmaley57
Из-за одного приложения меняются механизмы планирования во всей системе! Мелкософты - они такие))

А вы можете предложить иной способ надежного программного отсчета малых интервалов, кроме перенастройки шедулера?

Сообщение было отредактировано: 5 июн 20, 03:09
5 июн 20, 03:11    [22146046]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточность - исследование длительности квантов времени  [new]
rgreat
Member

Откуда:
Сообщений: 6019
misha mike,

Чем вас QueryPerformanceCounter не устраивает?
5 июн 20, 03:16    [22146048]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточность - исследование длительности квантов времени  [new]
misha mike
Member

Откуда:
Сообщений: 710
rgreat, всем устраивает, но измерять малый интервал -- это не то же самое, что выполнять некое действие с этим интервалом. Таймер дергает обработчик, а чтобы исполнять код каждую миллисекунду, нужно уметь переключать задачи как минимум с таким интервалом (а лучше чаще).
5 июн 20, 03:27    [22146050]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточность - исследование длительности квантов времени  [new]
rgreat
Member

Откуда:
Сообщений: 6019
misha mike,

Запроектируйте алгоритм так что бы это было не важно. Как уже было сказано выше Windows это не система реального времени.

Тот кто всерьез рассчитывает на обратное - любовно раскладывает сам себе грабли.

Сообщение было отредактировано: 5 июн 20, 03:37
5 июн 20, 03:37    [22146052]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточность - исследование длительности квантов времени  [new]
misha mike
Member

Откуда:
Сообщений: 710
rgreat
Запроектируйте алгоритм так что бы это было не важно.

Дело не в алгоритме, а в том, что в составе WinAPI есть таймер, который умеет срабатывать с периодом вплоть до миллисекунды. Реализовать такой таймер иным способом, кроме ускорения системного шедулера, -- невозможно. Microsoft не виноваты в том, что этот таймер работает именно так. Если они и виноваты в чем-то, то в том, что не написали об этом большими красными буквами в документации к безобидной на первый взгляд функции.
5 июн 20, 03:49    [22146054]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточность - исследование длительности квантов времени  [new]
rgreat
Member

Откуда:
Сообщений: 6019
misha mike,

var
  hTim: THandle;
  Delay: Int64;
begin
  hTim := CreateWaitableTimer(nil, false, nil);// создаем таймер
  Delay := -10000000;// Delay задается в сотнях наносекунд.
  SetWaitableTimer(hTim, Delay, 0, nil,nil,false); // задаем настройки
  WaitForSingleObjectEx(hTim, infinite, true);// ждем 
  ShowMessage('Прошла одна секунда');

Таймер можно сделать цикличным а вместо WaitForSingleObjectEx заюзать каллбэк.

Сообщение было отредактировано: 5 июн 20, 04:13
5 июн 20, 04:08    [22146059]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточность - исследование длительности квантов времени  [new]
rgreat
Member

Откуда:
Сообщений: 6019
http://www.windowstimestamp.com/description
5 июн 20, 04:27    [22146062]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточность - исследование длительности квантов времени  [new]
kealon(Ruslan)
Member

Откуда: Нижневартовск
Сообщений: 5952
misha mike
rgreat
Запроектируйте алгоритм так что бы это было не важно.

Дело не в алгоритме, а в том, что в составе WinAPI есть таймер, который умеет срабатывать с периодом вплоть до миллисекунды. Реализовать такой таймер иным способом, кроме ускорения системного шедулера, -- невозможно. Microsoft не виноваты в том, что этот таймер работает именно так. Если они и виноваты в чем-то, то в том, что не написали об этом большими красными буквами в документации к безобидной на первый взгляд функции.
вы бы разобрались для начала в вопросе каким образом планировщик задач получает управление - тынц
5 июн 20, 10:45    [22146217]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточность - исследование длительности квантов времени  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11913
DmSer
в диспетчере задач выполнить привязку процесса к одному ядру
SetThreadAffinityMask
DmSer
привязка потока к ядру процессора не является постоянной.
Чтобы не перегревать одно ядро
DmSer
При этом часто оказываются загружены несколько ядер
Дефект большой дискретизации диспетчера задач
DmSer
ОС старается распределить загрузку по всем доступным ядрам
Смотри выше. Равномерный разогрев
DmSer
Предполагаю, что поток отработал свой квант (предположим 50 мс), затем ОС его усыпила, но поскольку нет других потоков, которым нужен процессор, ОС тут же его пробуждает.
Смотри алгоритм работы планировщика
5 июн 20, 12:24    [22146311]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточность - исследование длительности квантов времени  [new]
Kazantsev Alexey
Member

Откуда:
Сообщений: 4469
_Vasilisk_
Чтобы не перегревать одно ядро

_Vasilisk_
Смотри выше. Равномерный разогрев

Нагрев проца это не забота ОС. Процы сейчас сами умеют даже частоты поднимать для отдельных ядер, если есть нагрузка и не превышается TDP.
5 июн 20, 12:47    [22146329]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточность - исследование длительности квантов времени  [new]
misha mike
Member

Откуда:
Сообщений: 710
kealon(Ruslan), и каким образом прерывание от таймера противоречит сказанному мной? Что вы вообще сказать хотели?
5 июн 20, 16:52    [22146503]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточность - исследование длительности квантов времени  [new]
kealon(Ruslan)
Member

Откуда: Нижневартовск
Сообщений: 5952
misha mike,

пардонс, промахнулся - это на это 22146059 сообщение был ответ
5 июн 20, 16:57    [22146507]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточность - исследование длительности квантов времени  [new]
misha mike
Member

Откуда:
Сообщений: 710
great, блокирующие функции типа WaitForSingleObject все равно завязаны на разрешающую способность шедулера. Они отпускают поток не мгновенно после изменения состояния ожидаемого объекта, а в лучшем случае тогда, когда отработает текущий поток, висящий на том же ядре. Да и то не факт, на ядро могут быть завязаны и другие потоки, которые тоже дождались разблокировки и квант получит один из них.

Сами сказали, что Windows -- не система реального времени, а значит не просто мгновенного, а вообще детерменированного по времени переключения контекста быть не может. В оптимистическом среднем случае это половина интервала работы шедулера. А в пессимистическом -- вообще многие секунды.

Что касается частой генерации события в цикле, то это детский сад. Мало того, что работа цикла будет прерываться другими потоками на неопределенное время, так еще и динамическое изменение частоты процессора сделает такой "таймер" неюзабельным.
5 июн 20, 17:03    [22146511]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
Все форумы / Delphi Ответить