异步睡眠循环

时间:2020-07-10 08:09:19

标签: c# async-await wait

因此对于我的项目,我需要每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
}

我已经尝试过一些异步等待的方法,但是我似乎无法理解。 谁能帮助我找到一种可靠的方法来获取100秒间隔的10秒测量结果?

编辑: 我知道,由于我在Windows上运行C#,因此计时实际上不是一个有效的选择。但这对我的问题并不重要。我的问题是,如何确保for循环至少要花100毫秒(!!!),而又要尽可能接近100毫秒。

1 个答案:

答案 0 :(得分:5)

一种方法是创建一个秒表,并在完成每个操作后等待其到达下一个里程碑。

这种方式的好处是:

  • 您将把循环的开销添加到混合中,调整延迟以进行补偿
  • 这样,它应该几乎没有“漂移”(根据何时发生操作,操作将逐渐“变后”)

这样的排序:

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也有一些开销的事实,因此开销可能仍然很小。

如果您对“刻录CPU”感到满意,则可以改为:

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

这将使您的操作运行得更接近实际的100毫秒标记,因为Task.DelayThread.Sleep的开销会导致延迟时间比预期的时间稍长。但是,它将在那10秒钟的时间内占用CPU内核。

相关问题