我遇到了所有可能的当前和过时的方法来实现在后台持续运行以获取数据然后由 UI 显示的方法的问题。
一般来说,我偶然发现了 async/await
用法 in this answer同时阅读各种计时器 in this answer .
我的场景如下:我想每 250 毫秒读取一次数据,并根据获取的数据更新我的 UI。一个天真的方法是像这样一个非常简单的调用:
while (true) {
// do stuff
Thread.Sleep(250);
}
这段代码不会每 250 毫秒调用一次,具体取决于主体中实际执行的时间!此外,与计时器特定的答案相比,我不想等到此方法完成后再次调用它,因此如果该方法在一个滴答声中花费的时间太长,我仍然想尽可能每 250 毫秒调用一次并中止如有必要,之前的报价执行。
我应该使用通用的 Timer
、DispatcherTimer
、Task
等吗?您是否有最新的进一步引用资料和相关问题?
最佳答案
因此,如果我理解正确的话,您希望每 250 毫秒运行一些代码。即使代码需要 40 毫秒,也不需要使用 Thread.Sleep(250)
等待 250 毫秒,因为总共需要 290 毫秒。
您可以使用 Timer
或使用类似这样的东西:
const int MaxAllowTimeInMs = 250;
async Task Main()
{
while(true)
{
var cts = new CancellationTokenSource();
cts.CancelAfter(MaxAllowTimeInMs);
try
{
await Task.WhenAll(new[]
{
MyTask(cts.Token),
Task.Delay(MaxAllowTimeInMs)
});
}
catch (OperationCanceledException)
{
// MyTask took longer than 250ms
}
}
}
async Task MyTask(CancellationToken ct)
{
// Get some data
...
ct.ThrowIfCancellationRequested();
// If you reach this point, you can process stuff knowing that it took less than 250ms to get it.
}
此代码允许 MyTask
在 250 毫秒内完成。如果需要更长的时间,结果将被丢弃。
如果您最终运行的代码也接受 CancellationToken
,请同时传递示例中的那个,以便能够真正取消操作。否则您实际上无法取消操作,但您可以在超过 250 毫秒时丢弃结果。
通过使用 Timer
,您可以采用相同的方法。在某种伪代码中:
const int MaxAllowTimeInMs = 250;
void Main()
{
var timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(MaxAllowTimeInMs);
timer.Tick += async (s, e) =>
{
using(var cts = new CancellationTokenSource())
{
try
{
cts.CancelAfter(MaxAllowTimeInMs);
await MyTask(cts.Token);
}
catch (OperationCanceledException)
{
// MyTask took longer than 205ms
}
}
};
timer.Start();
}
async Task MyTask(CancellationToken ct)
{
// Simulate some work
...
ct.ThrowIfCancellationRequested();
}
关于c# - 使用计时器/任务/后台 worker 的数据采集循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41532769/