异步睡眠循环
Async sleep in loop
所以对于我的一个项目,我需要每 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 秒的测量?
编辑:
我知道,因为我是 运行 C# on Windows,计时并不是一个真正有效的选项。但这在我的问题中并不重要。我的问题是,如何确保 for 循环至少需要(!!!) 100 毫秒,同时尽可能接近 100 毫秒。
一种方法是创建一个秒表,并在每次操作后等待它到达下一个里程碑。
这种方式的好处是:
- 您会将循环的开销添加到混合中,调整您的延迟以补偿
- 因此,它应该几乎没有“漂移”(操作将根据应该发生的时间逐渐“稍后”)
有点像这样:
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.Delay
和 Thread.Sleep
的开销往往会比您预期的延迟稍长.但是,它将在这 10 秒内占用一个 CPU 核心。
所以对于我的一个项目,我需要每 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 秒的测量?
编辑: 我知道,因为我是 运行 C# on Windows,计时并不是一个真正有效的选项。但这在我的问题中并不重要。我的问题是,如何确保 for 循环至少需要(!!!) 100 毫秒,同时尽可能接近 100 毫秒。
一种方法是创建一个秒表,并在每次操作后等待它到达下一个里程碑。
这种方式的好处是:
- 您会将循环的开销添加到混合中,调整您的延迟以补偿
- 因此,它应该几乎没有“漂移”(操作将根据应该发生的时间逐渐“稍后”)
有点像这样:
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.Delay
和 Thread.Sleep
的开销往往会比您预期的延迟稍长.但是,它将在这 10 秒内占用一个 CPU 核心。