我写了一个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
?
我错过了什么?
答案 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);
}