[英]await and async blocking the 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
? 我錯過了什么?
為什么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);
}
}
}
用async
關鍵字本身標記SearchPnrFilesAsync
的事實並沒有神奇地在單獨的任務中異步地開始執行此方法。
事實上,所有的碼的SearchPnrFilesAsync
除了sw.WriteAsync
執行UI線程從而阻止它。
如果你需要在單獨的任務中執行整個方法,你可以通過包裝如下:
public async static Task SearchPnrFilesAsync(string mainDir)
{
await Task.Run(() => your_code_here);
}
為什么UI線程卡住了
我已經測試過您發布的代碼不會阻止 UI。 當SearchPnrFilesAsync
運行時,我能夠調整 window 的大小並單擊按鈕。 您是否認為它被阻止是因為它沒有顯示“在 SearchPnrFilesAsync 之后”消息? 如果我錯了,請告訴我。
不立即顯示 MessageBox
button_FindFiles_Click
function 中的await
關鍵字等待SearchFilesUtil.SearchPnrFilesAsync
function 完成。 這就是為什么單擊按鈕后不會立即彈出“在 SearchPnrFilesAsync 之后”消息的原因。 如果您希望在單擊按鈕后立即執行SearchFilesUtil.SearchPnrFilesAsync
function 並立即檢查消息,則可以在不使用await
關鍵字的情況下調用該方法。
SearchFilesUtil.SearchPnrFilesAsync(this.textBox_mainDirectory.Text);
當您不在返回Task
的 function 上使用await
時,您將收到“警告”。 在這種情況下,使用discards
功能,警告將消失。 (配C# 7)
_ = SearchFilesUtil.SearchPnrFilesAsync(this.textBox_mainDirectory.Text);
如果您想了解更多信息,請查看此鏈接( https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/discards )
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.