我遇到了所有可能的当前和过时方法的问题,这些方法实现了一个在后台持续运行的方法,以获取随后由UI显示的数据。
一般来说,我偶然发现async/await
使用in this answer,同时还阅读了各种计时器in this answer。
我的方案如下:我想每250ms读取一次数据,并根据获得的数据更新我的UI。一个天真的方法是这样一个非常简单的调用:
while (true) {
// do stuff
Thread.Sleep(250);
}
此代码不会每250ms调用一次,具体取决于实体执行的时间长短!此外,与定时器特定的答案相反,我不想等到这个方法完成再次调用它,因此如果方法结果需要花费太长时间,我仍然希望尽可能准确地每隔250ms调用它并中止必要时执行上一个滴答。
我应该使用通用Timer
,DispatcherTimer
,Task
等吗?您是否有更新的参考资料和相关问题?
答案 0 :(得分:1)
因此,如果我理解正确,您希望每250毫秒运行一些代码。即使代码需要40ms,也不需要使用Thread.Sleep(250)
等待250ms,因为总共需要290ms。
您可以使用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();
}