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

Max*_*Max 2 c# multithreading async-await windows-runtime

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

    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();
        }
    }
Run Code Online (Sandbox Code Playgroud)

我在这里想要实现的是找到一个XAML的解决方法WebView,我发现它非常草率.我希望能够在它上面绘制内容,但我不能这样做,我基本上做的是重复(WebView使用WebViewBrush)快照(基于int FPS字段),然后设置Background画布的属性" webViewContent"有了这个快照.目的是在画布上显示动画,同时仍然可以在其上绘制(如果我不执行这些快速快照,画布将显示静止图像).

它现在工作正常(我成功地将任何Tapped事件重定向到内部,WebView以便正确处理按钮/链接/ ...的点击)但它有点滞后.慢慢的是wvb.Redraw()我想知道如何改善我的线程的性能.看起来UI在响应期间是响应的,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);
        }
Run Code Online (Sandbox Code Playgroud)

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

0,094
0,058
0,041
0,053
0,057
0,038
0,032
0,033
0,032
0,038
0,035
0,03
0,042
0,028
0,044
0,031
0,033
0,029
0,034
0,03
0,052
0,029
Run Code Online (Sandbox Code Playgroud)

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

Jon*_*eet 8

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

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

从根本上说,如果你的Redraw方法太慢而不能被调用〜每秒60次,你需要一个不同的方法.

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

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