等待和异步阻止UI

我写了一个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 ? 我错过了什么?

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

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

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

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

为什么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); } } }