c# - 使用计时器/任务/后台 worker 的数据采集循环

标签 c# wpf multithreading timer task

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

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

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

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

这段代码不会每 250 毫秒调用一次,具体取决于主体中实际执行的时间!此外,与计时器特定的答案相比,我不想等到此方法完成后再次调用它,因此如果该方法在一个滴答声中花费的时间太长,我仍然想尽可能每 250 毫秒调用一次并中止如有必要,之前的报价执行。

我应该使用通用的 TimerDispatcherTimerTask 等吗?您是否有最新的进一步引用资料和相关问题?

最佳答案

因此,如果我理解正确的话,您希望每 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/

相关文章:

C# 比 C++ 运行得更快?

c++ - 将 boost::lockfree 与 c++11 线程支持库一起使用是否安全?

c - 为什么clone创建的线程中无法正确调用malloc/free接口(interface)?

android - 在 android 后台收集和保存大量数据的最有效方法

c# Process.GetCurrentProcess().Threads.Count 在使用 MaxDegreeOfParallelism 时未返回预期?

c# - 第一次机会异常发生在 XMLSerializer 的构造函数中

c# - C# 使用和 Java 导入之间的区别

wpf - DataGridComboBoxColumn 单元格不显示所选项目文本?

C#数学图形库

c# - 延迟取消选择 ListBoxItem