2016-12-21 8 views
6

Я реализую алгоритм связи для отправки информации периодически и очень быстро, то есть 1 мс между пакетами. У меня есть функциональная версия, которая использует Tasks для отправки пакетов. Вот пример моего кода:Как ввести точную небольшую задержку в задаче без перегрузки процессора?

private void Work() 
{ 
    Stopwatch stopwatch = new Stopwatch(); 
    stopwatch.Start(); 

    while (!cancellationTokenSource.Token.IsCancellationRequested) 
    { 
     if (!Pack.PeriodicOn) 
      cancellationTokenSource.Cancel(); 

     // Time used to send the packs before the interval time 
     double tolerance = Pack.Interval * 0.2F; 

     // In case of interval bigger than 25ms send pasks only 5ms before 
     if (tolerance > 5) tolerance = 5; 

     TimeSpan timeSpan = stopwatch.Elapsed; 

     // The waiting time is controlled by the condition below, if the condition is false, the while loop continues execution   
     // Send the information a little bit before to interval time to deal with the transmision delay 
     if (Pack.LastSent.TotalMilliseconds == 0 || 
      timeSpan.TotalMilliseconds - Pack.LastSent.TotalMilliseconds >= 
      (Pack.Interval - tolerance)) 
     { 
      SendData(Pack); 
      Pack.LastSent = timeSpan; 
     } 
    } 

    Pack.LastSent = new TimeSpan(0); 
} 

Моя проблема основывается в том, что увеличивается использование процессора к нежелательному уровней. Я знаю, что я могу избежать этого, введя некоторую задержку, но, Thread.Sleep (1) очень неточен и реальный интервал передачи между пакетами увеличивается, если я использую wait.Delay (1), похоже, дает тот же эффект.

Есть ли у кого-нибудь альтернативный способ ввести, точно, задержать задачи?

Заранее благодарен!

+7

Windows не является оперативной ОС:/ –

+0

Другие ответы SO, например. http://stackoverflow.com/questions/6254703/thread-sleep-for -less-than-1-millisecond, похоже, говорит, что вращение процессора, как вы делаете, - это путь. –

+0

Было бы полезно понять, что вы подразумеваете под «очень неточным». Сколько различий вы видите? Какой интервал таймера вашей системы (по умолчанию - 15 мс) – EricLaw

ответ

0

Windows не работает в режиме реального времени, поэтому таймеры не гарантированно работают точно. Типичные системные часы имеют точность около 15 мс. Однако можно получить более точные события, чем стандарт System.Threading.Timer. В Windows API есть таймеры, предназначенные для мультимедийных сценариев, которые могут срабатывать с более точными интервалами. У меня есть обновление кода в репо GitHub я утверждаю, HighPrecisionTimer, которая использует, что API, чтобы включить на основе MultimediaTimer.Delay метод Задачу:

private static async Task RunEveryMillisecond(CancellationToken token) 
{ 
    Stopwatch s = Stopwatch.StartNew(); 
    TimeSpan prevValue = TimeSpan.Zero; 
    int i = 0; 
    while (true) 
    { 
     Console.WriteLine(s.ElapsedMilliseconds); 
     await MultimediaTimer.Delay(1, token); 
     if (Console.KeyAvailable) 
     { 
      return; 
     } 

     i++; 
    } 
} 

Обратите внимание, что это пожары примерно каждые 1,5 мс в моей системе, и он все еще может ударить CPU около 10% при запуске, поэтому это не является незначительным ударом по системным ресурсам. Стандартный метод таймера, включенный в проект, немного более точен и эффективен (меньше затрат на процессор, ~ 1%) для запуска методов на уровне 1 мс. Я предполагаю, что в методе задержки на основе задач больше затрат на распределение и сбор мусора.

Обратите внимание, что использование этого API может иметь побочные эффекты, такие как сокращение срока службы батареи. Однако это полезно для сценариев типа теста, где требуются более короткие тайминги.

+0

Большое спасибо !, накладные расходы процессора (~ 20% для всего приложения, использующего связь) ничто не сравнивает с тем, что я (до 80% и выше), я могу справиться с этим. В случае срока службы батареи я должен проверить производительность, но мне кажется, что у меня не будет проблем, так как периоды общения не слишком длинные, и я останавливаю таймер при простоях, спасибо! ;) – YRod

1

Как ввести точную небольшую задержку [1мс] без перегрузки ЦП [в Windows]?

Вы не можете, извините. Системный планировщик на окнах только слегка настраивается (выбрав Adjust for best performance of Applications в диалоговом окне расширенных системных свойств для Windows Server или setting a registry value), но он не будет входить в субмиллисекундную территорию. Если это произойдет, производительность всей системы будет неприемлемой.

В зависимости от вашего оборудования, я думаю, что может быть можно уменьшить системное тактное разрешение до 0,5 мс; тем не менее, минимальный квант нити, который вы можете установить, равен 6, что потребует двух тактов, чтобы уменьшить до 0. Таким образом, вы все равно получите квант в 1 мс, который по крайней мере в два раза медленнее, чем вам нужно. И, конечно же, вы сократите время автономной работы на ~ 15% (из того, что я прочитал).

Дополнительную информацию см. Windows Internals.

0

вы можете начать много последовательных потоков сказать n (n = 10 или 20 и т. Д.) (N - количество потоков) после 1 мс задержки, и в каждой задаче вы можете подождать n миллисекунд.