c# - 如何防止我的异步方法阻塞 UI?

标签 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. 您处理许多行的速度如此之快,以至于 UI 线程一直忙于更新,没有时间实际显示结果。要解决此问题,请不要报告每一行的进度,而是仅每 100、1000 或任何适合您的行数报告一次。作为替代方案,您可以根据时间(例如每秒)报告进度。但这需要更复杂的代码。
  2. 您遇到了 Task.Factory.StartNew() 的问题,它在 UI 线程上运行,因为那是 Current TaskScheduler。尽管我在您的代码中没有看到任何迹象表明是这种情况,所以我认为这不太可能。但是为了安全起见,您应该改用 Task.Run()。有关详细信息,请阅读 StartNew is Dangerous from Stephen Cleary .

关于c# - 如何防止我的异步方法阻塞 UI?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37759763/

相关文章:

java - 在 JPanel java 中显示多边形的坐标

winapi - 自动调整静态控件大小的正确方法是什么?

c# - 在 ADO.Net 实体模型中,如何将带有外键的表更新为另一个表?

c - 在 C 中的 Windows 上中断 Sleep()

c++ - 澄清 CSingleLock 的作用及其使用的同步对象

java - 取消异步调用

qt - 我怎样才能拥有 QMainWindow 的 UI?

C# WebBrowser 控件——在 AJAX 之后获取文档元素?

c# - 从日期列中获取按月过滤的行

c# - 将 List<double[]> 转换为 List<T>