2013-06-20 56 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

相關問題