简体   繁体   中英

await and async blocking the UI

I wrote a little winforms application that search for files on the disk (what file is not that important for the sake of the question). the problem is the that it can be even 100,000 files or so. so this operation takes time.

What I want to achieve is to do the search operation as an async operation and not to block the UI thread so the form won't get stuck.

I can do this with the backgroundWorker but for some reason not with the async\await mechanism.

Here is my code:

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);
        }
    }
}

Why is the UI thread get stuck and not displaying the MessageBox immediately? what am I missing?

Why does the UI thread get stuck?

Probably because you have some blocking work done on the UI thread, such as reading a file.

Why is my MessageBox not displayed immediately?

Because that is not how async works. When you await a method, it asynchronously yields control to the caller until the operation is done. When the first await is hit, you start reading files from disk and copying them. await does not mean "execute this on a different thread and continue".

What you probably want to do is use an asynchronous reading mechanism instead of the blocking File.ReadAllText . You can do this using 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);
        }   
    }   
}

The fact of marking SearchPnrFilesAsync with async keyword itself doesn't magically starts execution ot this method asynchronously in separate task.

In fact, all of the code in SearchPnrFilesAsync except sw.WriteAsync executes in UI thread thus blocking it.

If you need to execute your whole method in separate task, you can do it by wrapping like:

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

Why is the UI thread get stuck

I've tested the code you posted doesn't make UI blocked. When SearchPnrFilesAsync running, I was able to resize the window and click the button as well. Did you think it was blocked because it didn't show the "After SearchPnrFilesAsync" message? If Something I wrong, please let me know.

not displaying the MessageBox immediately

The await keyword inside the button_FindFiles_Click function waits for the SearchFilesUtil.SearchPnrFilesAsync function to finish. That's why "After SearchPnrFilesAsync" message doesn't pop up as soon as the button is clicked. If you want the SearchFilesUtil.SearchPnrFilesAsync function to be executed as soon as you click the button and immediately you want to check the message, you can call the method without await keyword.

SearchFilesUtil.SearchPnrFilesAsync(this.textBox_mainDirectory.Text);

When you don't use await on a function that returns a Task , you'll get a "warning". In this case, use discards feature and the warning will disappear. (With C# 7)

_ = SearchFilesUtil.SearchPnrFilesAsync(this.textBox_mainDirectory.Text);

If you want to know more about it, please check out this link ( https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/discards )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM