2017-01-26 2 views
4

Я использую System.Threading Timers для опроса датчиков на разных потоках (по одному задержка была медленной из-за латентности связи). Он также позволяет пользователю изменять скорость голосования, изменяя период таймера.Что происходит, когда таймерные потоки не заканчиваются вовремя

Что я не могу решить, что произойдет, если таймеры не закончатся до следующего периода. Я написал тестовую программу, но на самом деле ничего не ответил.

Если у меня есть функция, которая запускает ~ 1.7s и вызывает ее каждые 10 секунд, она заканчивается до следующего запуска, а использование моего процессора колеблется между 13% (один ядро ​​100%) и 0%.

t = new Timer(doWork, null, 0, 10000); 

private void doWork(object o) 
{ 
    for(int i = 0; i < numberItts; i++) 
    { 
    } 
} 

Если я затем опустите период таймера на 1 сек, я бы ожидать, что она либо не выполнять поток, пока предыдущий не будет закончена, или сохранить порождая новые темы и использование процессора будет подниматься, как больше потоков начинают перед другими Конец. Фактически, использование ЦП колеблется от 13% до 25%.

Изменение периода до 500 мс, использование ЦП колеблется от 38% до 50%. Разумеется, в этот момент они должны начинаться гораздо быстрее, чем они заканчиваются.

Как справляются эти потоки? Что ограничивает количество, созданное, когда частота опроса быстрее, чем скорость, с которой потоки могут быть завершены?

ответ

7

В отличие от System.Windows.Forms.Timer, System.Threading.Timer использует пул потоков и не подлежит блокируется, если ваш обработчик таймера занимает больше времени, чем интервал таймера для завершения.

Так что, если ваш doWork занимает около «~ 1.7s» для завершения и ваш интервал таймера один второй, можно было бы ожидать, чтобы увидеть несколько параллельных потоков ввода doWork.

Как справляются эти потоки? Что ограничивает количество, созданное, когда частота опроса быстрее, чем скорость, с которой потоки могут быть завершены?

Это все обрабатывается классом Timer и ассоциированным пулом потоков.

MSDN это сказать:

Метод обратного вызова выполняется с помощью таймера должен быть повторно, так как он вызывается Threadpool нитями. Обратный вызов может выполняться одновременно в двух потоках пула потоков, если интервал таймера меньше времени, необходимого для выполнения обратного вызова, или все потоки пулов потоков используются, а обратный вызов ставится в очередь несколько раз. more...

Поэтому, учитывая этот кусок кода, где интервал таймера составляет 2 секунды и время обработки обработчик 1 вторых, мы можем ожидать того же самого потока каждый раз, потому что его вообще лучше повторно использовать ту же нить, чем спина до нового:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var t = new Timer(doWork, null, 0, 1000); 


     Console.WriteLine("Press any key to quit"); 
     Console.ReadKey(); 
    } 

    private static void doWork(object o) 
    { 
     Console.WriteLine("Thread: {0}", Environment.CurrentManagedThreadId); 

     // simulate lengthy process 
     Thread.Sleep(1000); 
    } 
} 

enter image description here

Изменения времени интервала и обработки до 1 секунды, приводит к случайным потокам из-за слабое перекрытие.

enter image description here

Изменение интервала 200 мс и сохранение времени обработки до 1 секунды приводит к увеличению числа рабочих потоков, чем раньше. Причина в том, что пул потоков осознал, что делегаты принимают больше времени, чем интервал таймера поэтому он пытается угнаться:

enter image description here

2

Я думаю, что происходит следующее за период таймера 1s:

  • через 0 секунды: начата нить 1. Один процессор занят -> ~ 13%
  • через 1 секунду: начинается воспроизведение темы 2. Два процессора заняты -> ~ 25%
  • на 1,7 секунды: нить 1 завершена. Только один процессор занят -> ~ 13%
  • через 2 секунды: запускается Thread 3. Два процессора заняты -> ~ 25%
  • через 2,7 секунды: Thread 2 завершен. Только один процессор занят -> ~ 13%
  • ...

Т.е. все же потоки обрабатываются быстрее, чем они созданы. Даже в течение 500 мс это будет правдой.

Я думаю, что поведение, которое вы ожидали, произойдет, когда вы уменьшите период таймера до значения < 1.7s/8 = ~ 0.2125s (Предполагая, что у вас есть 8 процессоров, ничего не делая, кроме как обрабатывать ваши потоки, которые занимают их 1.7s.)

+0

«Я думаю, что поведение, которое вы ожидали, произойдет, когда вы уменьшите период таймера до значения <1.7s/8 = ~ 0.2125s» Это имеет большой смысл, спасибо. – MikeS159

Смежные вопросы