为什么这个异步方法会阻塞UI线程?

时间:2013-06-20 15:14:50

标签: c# multithreading windows-runtime async-await

我正在努力解决这段代码引发的问题:

    private int FPS = 60;

    void WebView_LoadCompleted(object sender, NavigationEventArgs e)
    {
        WebviewContentWorker();
    }

    private async void WebviewContentWorker()
    {
        WebViewBrush wvb = new WebViewBrush();
        wvb.SetSource(WebView);
        wvb.Redraw(); //we must redraw at least once before collapsing the WebView
        WebView.Visibility = Windows.UI.Xaml.Visibility.Collapsed;

        while (true)
        {
            webViewContent.Background = wvb; //webViewContent is a canvas
            await Task.Delay(1000 / FPS);
            wvb.Redraw();
        }
    }

我在这里想要实现的是找到XAML的WebView的解决方法,我发现它非常草率。我希望能够在它上面绘制内容,但我不能这样做,我基本上做的是重复拍摄WebView(使用WebViewBrush)的快照(基于{{ 1}} field)然后使用此快照设置名为“int FPS”的画布的Background属性。目的是在画布上显示动画,同时仍然能够在其上绘制(如果我不执行这些快速快照,画布将显示静止图像)。

现在工作正常(我成功地将任何webViewContent事件重定向到Tapped的内部,以便正确处理按钮/链接/ ...的点击次数,但它有点滞后。缓慢的位是WebView我想知道如何改善线程的性能。在 wvb.Redraw()期间,用户界面似乎是的响应,但是否则会被阻止...

非常欢迎任何意见/建议!

编辑: 以下是我为Task.Delay调用计时的时间(我认为这是导致问题的原因,因为删除它会使应用程序响应很快):

Redraw

在输出窗口中给出了这些结果:

        while (true)
        {
            webViewContent.Background = wvb;
            await Task.Delay(1000 / FPS);
            sw.Reset();
            sw.Start();
            wvb.Redraw();
            sw.Stop();
            System.Diagnostics.Debug.WriteLine(sw.Elapsed.TotalMilliseconds);
        }

毕竟不是那么多......

2 个答案:

答案 0 :(得分:9)

  

看起来UI在Task.Delay期间是响应的,但是否则被阻止......

是的。那正是正在发生的事情。 Task.Delay是您提供UI线程工作的唯一机会。您的异步方法正在UI线程上执行 - 一旦“延迟”任务完成,您将最终继续等待在UI线程上执行,该线程将重绘然后再次延迟。

从根本上说,如果Redraw方法太慢而无法每秒调用60次,则需要采用不同的方法。

理解async 将方法放在不同的线程上非常重要 - 它只允许您异步操作。 (您的描述和标题表明您希望您的方法在任何重要时间都不使用UI线程。)

另外,正如Stephen Cleary所说,使用DispatcherTimer是在UI线程上定期执行代码的一种更好的方法。

答案 1 :(得分:2)

Task.Delay对于反复进行多次短暂超时并不是特别有效。你会产生很多垃圾。

我建议在这种情况下使用调度程序计时器或类似工具。