2013-06-20 59 views
2

我与通过这段代码提出的一个问题挣扎:为什么这个异步方法阻塞UI线程?

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)的快照(基于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); 
     } 

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

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 

所以没有那么多毕竟...

+0

您的'Redraw'方法运行多长时间?另外,有60 FPS真的是必要的吗?你可以降低它一点,而不显示太生涩? – Servy

+0

我今天试过使用'StopWatch' ealier,我相信'(double)Elapsed.TotalMilliseconds'属性返回了0,1XXX和0,3XXX之间的值。 – Max

+0

如果花费了三分之一毫秒,那么即使每秒完成60次,我也看不到它会如何阻挡用户界面足够长的时间才能被某个人察觉。 UI仍然有足够的时间让消息循环保持响应。也许你没有在与你实际使用它相同的条件下正确计时。 – Servy

回答

9

它看起来像UI在Task.Delay期间是敏感的,但被阻止,否则...

好的。那是究竟是发生了什么事。 Task.Delay是您让UI线程发挥作用的唯一机会。您的异步方法正在UI线程上执行 - 只要“延迟”任务完成,您将最终得到一个延续,等待在UI线程上执行,该线程将重绘然后再次延迟。

基本上,如果您的Redraw方法太慢而不能被称为每秒60次,则需要采用不同的方法。

理解这一点很重要,async不会将该方法放到不同的线程上 - 它只是允许您异步操作。 (您的描述和标题暗示您预计您的方法不会在任何显着的时间使用UI线程。)

此外,正如Stephen Cleary所说,使用DispatcherTimer是定期在UI线程。

+0

感谢您的解释,我确实认为'async'会在不同的线程上自动构建FSM。你写过关于寻找不同的方法,你有任何线索或想法吗? – Max

+0

@RedPolygon:呃,基本上你需要让'Redraw'更快或者更少的执行 - 就像那样简单。或者,如果可以的话,可以将一些重绘工作踢到不同的线程,但是如果没有更多信息,很难知道。 –

+0

在另一个线程中做一些'Redraw'工作会很棒,但是我没有写这个方法,所以我会看看我是否足够勇于潜入MSIL(我刚开始学习WinRT)。让我们希望一个更好的'WebView'随8.1一起发布,也许我们将在下周的BUILD活动中了解更多。无论如何,感谢您的建议。 – Max

2

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

我会建议在这种情况下使用调度计时器或类似的。

+1

尽管我同意'Task.Delay'在这里不是一个理想的选择,我不会期望'Task.Delay'产生的垃圾数量真的很重要。它至多只会被称为每秒60次,毕竟...和GC可以处理*真的*相当多的垃圾... –

+0

谢谢你的提示,它的工作更好一点,但它仍然是非常滞后。我在画布的顶部有一个自定义控件,您可以四处移动,并且可以定义感觉延迟。 – Max

相关问题