2016-06-11 51 views
2

所以我正在寫一個方法,該方法應該處理大量的字符串並更新處理過的每個字符串的UI。我正在使用async-await模式來使用Progress記者,它將字符串報告給應該更新的主線程。 問題是:它不起作用。即使我使用了await關鍵字,用戶界面也會被阻塞,就好像該方法同步運行一樣。 這裏是我的代碼如下所示:如何讓我的異步方法阻止用戶界面?

private async Task ProcessFile(string filePath, IProgress<string> progress) 
    { 
     string[] LinesToProcess = File.ReadAllLines(filePath); 
     int LineCount = Buffer.Count(); 

     await Task.Factory.StartNew(() => 
     { 
      for (int i = 0; i < Buffer.Count(); i++) 
      { 
       //Do actual processing here 
       progress.Report(string.Format("Lines processed: {0}/{1}", i, LineCount)); 
      } 
     }); 
    } 

而這裏的調用ProcessFile任務

private async Task RunTask() 
    { 
     string filePath = //Get filePath somehow 
     await ProcessFile(filePath, new Progress<string>(line => 
      { 
       ProcessedLabel.Text = line; 
      })); 
    } 

的方法最後,這裏的按鈕回調的RunTask()任務有關:

private async void Button_Click(object sender, EventArgs e) 
    { 
     await RunTask(); 
    } 

我簡化了代碼的可讀性。任何幫助是極大的讚賞。謝謝!

+0

'File.ReadAllLines(filePath);'會這樣做,讀取所有行,所以如果存在多行的話,您最好逐行讀取。這可能有幫助。我只是新來的異步我自己 –

+0

你有沒有嘗試添加ConfigureAwait(false)到ProcessFile函數調用,因爲很多次我看到了UI塊。 – Chasefornone

回答

0

我可以看到兩個選項:

  1. 你如此迅速地處理多行的UI線程正在不停地忙碌着更新,也沒有時間來實際顯示結果。爲了解決這個問題,不要爲每條線報告進度,但每100,1000或任何線數適合您。作爲替代,您可以基於時間報告進度,例如每秒。但是那需要更復雜的代碼。
  2. 您遇到的問題是Task.Factory.StartNew(),它在UI線程上運行,因爲這是CurrentTaskScheduler。雖然我的代碼中沒有看到任何跡象表明事實如此,但我認爲這不太可能。但是,無論如何,您應該使用Task.Run()來保證安全。欲瞭解更多信息,請閱讀StartNew is Dangerous from Stephen Cleary
+2

爲什麼downvote?雖然我同意'Task.Run'更好,但UI阻塞問題幾乎肯定是由於(1)。這是因爲[Windows上的UI消息循環優先,而'WM_PAINT'是最低優先級](https://msdn.microsoft.com/en-us/library/windows/desktop/ms644927(v = vs.85)的.aspx#quequed_messages)。 –

+0

所以我嘗試了兩種選擇,而這些都沒有解決問題。更新UI每100次運行'for'循環會使代碼運行得更快,但UI仍然被阻塞。 另外,我試過使用調試器,如果我在'ProcessedLabel.Text = newReport;'行設置了一個斷點,我看到,通過跨越它,該行被連續調用,即使我設置了它每100次更新一次! – CRefice

+0

@CRefice然後嘗試1000,甚至更多。它看起來像你的處理速度非常快,你必須根據它來設置數字。如果你看到的行在調試器中處於活動狀態,但它沒有任何作用,那麼這很可能只是一個調試器故障。 – svick

相關問題