【问题标题】:Tasks freezing the interface任务冻结界面
【发布时间】:2017-09-05 04:34:08
【问题描述】:

我正在使用 3 个任务同时执行 3 个任务,但是,当启动所有任务时,GUI 没有冻结,它只会变得有点慢......当它返回最后一个任务的结果时,它会完全冻结并停止更新 GUI ...

async Task UpdateBlockChain()
        {
            var task = Task.Factory.StartNew((Action) =>
            {
                while (true)
                {
                    BlockChain blockChain = new BlockChain();
                    coinList[0].Price = blockChain.GetDataByNode("last");
                    coinList[0].Low = blockChain.GetDataByNode("low");
                    coinList[0].High = blockChain.GetDataByNode("high");
                    RefreshView();
                    Task.Delay(1000);
                }
            }, TaskScheduler.FromCurrentSynchronizationContext());

            await Task.Delay(500);
        }

        async Task UpdateBitFinex()
        {
            var task = Task.Factory.StartNew((Action) =>
            {
                while (true)
                {
                    Bitfinex bitFinex = new Bitfinex();
                    coinList[1].Price = bitFinex.GetDataByNode("last_price");
                    coinList[1].Low = bitFinex.GetDataByNode("low");
                    coinList[1].High = bitFinex.GetDataByNode("high");
                    RefreshView();
                    Task.Delay(2000);
                }
            }, TaskScheduler.FromCurrentSynchronizationContext());

            await Task.Delay(500);
        }

        async Task UpdateBitstamp()
        {
            var task = Task.Factory.StartNew((Action) =>
            {
                while (true)
                {
                    Bitstamp bitstamp = new Bitstamp();
                    coinList[2].Price = bitstamp.GetDataByNode("last");
                    coinList[2].Low = bitstamp.GetDataByNode("low");
                    coinList[2].High = bitstamp.GetDataByNode("high");
                    RefreshView();
                    Task.Delay(1000);
                }
            }, TaskScheduler.FromCurrentSynchronizationContext());

            await Task.Delay(500);
        }

刷新视图:

void RefreshView()
        {
            if (dataGridView1.InvokeRequired)
            {
                dataGridView1.BeginInvoke(new Action(() =>
                {
                    dataGridView1.Update();
                    dataGridView1.Refresh();
                }));
            }
        }

运行任务:

await UpdateBlockChain();
await UpdateBitFinex();
await UpdateBitstamp();

这是https://pastebin.com/DuQybhcz类的示例

我不知道我使用的方法是错误的,对于代码流错误我深表歉意。

【问题讨论】:

  • 您使用的是哪个 .NET 版本?如果是 452,那么您应该使用 Task.Run(() => {}) 而不是 Task.Factory.StartNew
  • 我使用 NET 4.5.1
  • 永远做await Task.Delay()
  • 由于您没有在无限循环中等待(正如@DennisKuypers 所说),因此您正在淹没 UI。
  • @ironstone13 however still if they would not run on UI thread - the UI would not freeze 不正确。任务发送的消息比 UI 处理的要多(别忘了 UI 更新很慢。)

标签: c# task


【解决方案1】:

这是因为您使用了TaskScheduler.FromCurrentSynchronizationContext,它应该安排任务在与调用线程相同的线程上运行,在您的情况下是 UI 线程。

将您的所有工作卸载到后台线程,并且仅使用 BeginInvoke 将 UI 刷新操作编组到您的 UI 线程

此外,您绝对必须在 while 循环内调用 await Task.Delay(xxx),否则循环之间不会出现延迟,而且它们会占用大量 CPU,并安排过多的 UI 更新

TaskScheduler引用MSDN

您可以使用 TaskScheduler.FromCurrentSynchronizationContext 方法 指定一个任务应该被安排在一个特定的 线。这在 Windows 窗体和 Windows 等框架中很有用 访问用户界面对象的 Presentation Foundation 通常仅限于在同一线程上运行的代码 UI 对象已创建。有关详细信息,请参阅如何:计划 处理用户界面 (UI) 线程。

以下示例使用 Windows 中的 TaskScheduler.FromCurrentSynchronizationContext 方法 Presentation Foundation (WPF) 应用程序在同一位置安排任务 创建用户界面 (UI) 控件的线程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-05
    • 2020-06-21
    • 2014-05-05
    • 1970-01-01
    • 2016-07-22
    • 2017-10-21
    相关资源
    最近更新 更多