使用计时器/任务/后台工作程序

时间:2017-01-08 12:37:18

标签: c# wpf multithreading timer task

我遇到了所有可能的当前和过时方法的问题,这些方法实现了一个在后台持续运行的方法,以获取随后由UI显示的数据。

一般来说,我偶然发现async/await使用in this answer,同时还阅读了各种计时器in this answer

我的方案如下:我想每250ms读取一次数据,并根据获得的数据更新我的UI。一个天真的方法是这样一个非常简单的调用:

while (true) {
    // do stuff
    Thread.Sleep(250);
}

此代码不会每250ms调用一次,具体取决于实体执行的时间长短!此外,与定时器特定的答案相反,我不想等到这个方法完成再次调用它,因此如果方法结果需要花费太长时间,我仍然希望尽可能准确地每隔250ms调用它并中止必要时执行上一个滴答。

我应该使用通用TimerDispatcherTimerTask等吗?您是否有更新的参考资料和相关问题?

1 个答案:

答案 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();
}