等待和异步阻止UI

时间:2015-12-08 08:44:27

标签: c# .net winforms asynchronous async-await

我写了一个winforms应用程序来搜索磁盘上的文件(为了这个问题,哪个文件并不重要)。问题是它甚至可能是100,000个文件。所以这个操作需要时间。

我想要实现的是将搜索操作作为异步操作而不是阻止UI线程,这样表单就不会卡住。

我可以使用backgroundWorker执行此操作,但由于某些原因没有使用async \ await机制。

这是我的代码:

private async void button_FindFiles_Click(object sender, EventArgs e)
{
    await SearchFilesUtil.SearchPnrFilesAsync(this.textBox_mainDirectory.Text);
    MessageBox.Show("After SearchPnrFilesAsync");
}

public async static Task SearchPnrFilesAsync(string mainDir)
{
    foreach (string file in Directory.EnumerateFiles(mainDir, ".xml", SearchOption.AllDirectories))
    {
        var fileContenet = File.ReadAllText(file);
        var path = Path.Combine(@"C:\CopyFileHere", Path.GetFileName(file));
        using (StreamWriter sw = new StreamWriter(path))
        {
            await sw.WriteAsync(fileContenet);
        }
    }
}

为什么UI线程卡住而不立即显示MessageBox? 我错过了什么?

2 个答案:

答案 0 :(得分:2)

  

为什么UI线程会卡住?

可能是因为您在UI线程上完成了一些阻塞工作,例如读取文件。

  

为什么我的MessageBox不会立即显示?

因为这不是async的工作方式。当你await一个方法时,它会异步地控制调用者,直到操作完成。当第一个await被命中时,您开始从磁盘读取文件并复制它们。 await并不意味着"在另一个线程上执行此操作并继续"。

您可能想要做的是使用异步读取机制而不是阻止File.ReadAllText。您可以使用StreamReader

执行此操作
public static async Task SearchPnrFilesAsync(string mainDir)
{
    foreach (string file in Directory.EnumerateFiles(mainDir, ".xml",
                                                        SearchOption.AllDirectories))
    {
        var path = Path.Combine(@"C:\CopyFileHere", Path.GetFileName(file));
        using (var reader = File.OpenRead(file))
        using (var writer = File.OpenWrite(path))
        {
            await reader.CopyToAsync(writer);
        }   
    }   
}

答案 1 :(得分:0)

使用SearchPnrFilesAsync关键字本身标记async的事实并没有神奇地在单独的任务中异步开始执行此方法。

实际上,SearchPnrFilesAsync中除sw.WriteAsync之外的所有代码都在UI线程中执行,从而阻止了它。

如果您需要在单独的任务中执行整个方法,可以通过包装如下来执行:

public async static Task SearchPnrFilesAsync(string mainDir)
{
   await Task.Run(() => your_code_here);
}