簡體   English   中英

等待和異步阻塞 UI

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM