2016-06-11 235 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