Асин c засыпать в цикле - PullRequest
2 голосов
/ 10 июля 2020

Итак, для моего проекта мне нужно получать значения с устройства каждые 100 мс. Выборка занимает x миллисекунд. Я ищу, но не могу найти способ убедиться, что for / while всегда занимает 100 мс (или больше).

Итак, в псевдокоде:

for (int i = 0; i < 100; i++) // Take measurements for 10 seconds
{
    // Call some async method that sleeps for 100 ms
    this.temperatureList.Add(this.HardwareManager.GetSensorValue(ESensor.Temperature)); // Takes 15 ms
    this.temperatureList.Add(this.HardwareManager.GetSensorValue(ESensor.Pressure)); // Takes 30 ms
    // await async method to finish
}

I пробовал некоторые вещи asyn c await с этим, но я не могу этого понять. Любой, кто может помочь мне найти надежный способ получить 10 секунд измерений с интервалом 100 мс?

РЕДАКТИРОВАТЬ: Я знаю, что, поскольку я запускаю C# на Windows, время на самом деле не допустимый вариант. Но в моем вопросе это не имеет особого значения. Мой вопрос: как я могу убедиться, что для l oop требуется не менее (!!!) 100 мс, при этом максимально приближаясь к 100 мс.

1 Ответ

5 голосов
/ 10 июля 2020

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

Преимущество этого способа в том, что:

  • Вы добавите в микс служебные данные l oop, регулируя задержку для компенсации
  • Таким образом, он не должен иметь практически никакого «дрейфа» (где операции будут постепенно выполняться «позже» в соответствии с когда они должны были произойти)

Примерно так:

var sw = Stopwatch.StartNew();
long next = 100;
while (sw.ElapsedMilliseconds < 10000)
{
    // do your operation here
    long left = next - sw.ElapsedMilliseconds;
    if (left > 0)
        await Task.Delay((int)left);
    next += 100;
}

Из-за точности ваших операций будет около каждые 100 миллисекунды, но они не должны дрейфовать.

Если вы в порядке с привязкой потока на эти 10 секунд, вы можете отключить часть задержки с помощью Thread.Sleep:

if (left > 0)
    Thread.Sleep((int)left);

Он будет выполнять ваши операции ближе к отметке 100 миллисекунд, но все же может иметь небольшие накладные расходы из-за того, что Thread.Sleep также имеет некоторые накладные расходы.

Если вас устраивает " горящий процессор ", вы можете сделать это вместо: * 1 025 *

var sw = Stopwatch.StartNew();
var next = 100;
while (sw.ElapsedMilliseconds < 10000)
{
    // do your operation here
    
    while (sw.ElapsedMilliseconds < next) ;
    next += 100;
}

Это запустит вашу операцию еще ближе к фактической отметке в 100 миллисекунд, поскольку Task.Delay и Thread.Sleep будут иметь накладные расходы, которые будут иметь тенденцию задерживаться немного дольше, чем вы планировали. Тем не менее, он будет ie активировать ядро ​​ЦП в течение этих 10 секунд.

...