如何防止异步方法阻止UI?

时间:2016-06-11 03:57:39

标签: c# multithreading user-interface asynchronous async-await

所以我正在编写一个应该处理大量字符串的方法,并为每个处理过的字符串更新UI。我正在使用async-await模式使用Progress报告器,该报告器将字符串报告给应该更新它的主线程。 问题是:它不起作用。即使我使用了await关键字,UI也会被阻塞,就像方法同步运行一样。 这是我的代码的样子:

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();
    }

我简化了代码的可读性。任何帮助是极大的赞赏。谢谢!

1 个答案:

答案 0 :(得分:0)

我可以看到两个选项:

  1. 您正在快速处理许多行,以至于UI线程一直忙于更新,并且没有时间实际显示结果。要解决此问题,请不要报告每一行的进度,但只有每100,1000或更多行适合您。作为替代方案,您可以根据时间报告进度,例如每秒。但这需要更复杂的代码。
  2. 您遇到的问题是Task.Factory.StartNew(),它在UI线程上运行,因为那是Current TaskScheduler。虽然我在代码中没有看到任何迹象表明这种情况,所以我认为这不太可能。但无论如何,您应该使用Task.Run()来保证安全。有关详细信息,请阅读StartNew is Dangerous from Stephen Cleary