c# - 为什么带有 await 关键字的异步方法仍然阻塞主线程?

标签 c# async-await task

任何人都可以向我解释这两种异步方法之间的区别吗?

方法一

public async Task<List<Thumbnail>> GetAllThumbnailsAsync()
{
    return await Task.Factory.StartNew(() =>             
    {
        var imageUris = GetAllDirectoriesWithImageAsync(CommandBaseUri).Result;

        return imageUris.Select(GetThumbnail).OrderByDescending(t => t.ImageDateTime).ToList();
    });
}

方法二

public async Task<List<Thumbnail>> GetAllThumbnailsAsync()
{
    var imageUris = await GetAllDirectoriesWithImageAsync(CommandBaseUri);

    return imageUris.Select(GetThumbnail).OrderByDescending(t => t.ImageDateTime).ToList();           
}

根据我的理解,这两种方法都应该返回给调用者并且不会阻塞 UI 线程,但在这种情况下,只有方法 A 按预期工作,而方法 B 会阻塞我的 UI。

我相信一定有一些我在使用 async/await 时可能误解了的基本概念。

谁能教教我?

最佳答案

方法 A 基本上是在一个单独的任务中执行一切,这可能会在一个新线程中结束。当您等待结果任务时,您不会阻止任何东西。

方法 B 首先调用 GetAllDirectoriesWithImageAsync,然后等待结果。这意味着当异步操作正在处理时,您不会阻塞 UI 线程 - 但默认情况下,当您等待任务时,这意味着延续将在 UI 线程中运行。所以 imageUris.Select(...).OrderByDescending(...).ToList() 将在 UI 线程中运行,我怀疑 这就是导致的部分用户界面中的问题。

现在您可以GetAllThumbnailsAsync 的第一行末尾调用 .ConfigureAwait(false),以表明您不需要需要在 UI 线程上执行第二部分 - 但这不能保证您不会在 UI 线程上执行第二部分。相反,在我看来,您真的想要一种获取缩略图的异步方式。然后你可以这样做:

public async Task<List<Thumbnail>> GetAllThumbnailsAsync()
{
    var imageUris = await GetAllDirectoriesWithImageAsync(CommandBaseUri)
        .ConfigureAwait(false);

    var thumbnailTasks = imageUris.Select(GetThumbnailAsync).ToList();
    var thumbnails = await Task.WhenAll(thumbnailTasks).ConfigureAwait(false);

    // I'm assuming there will be sufficiently few thumbnails here
    // that sorting them on the UI thread wouldn't be a problem, in
    // the unlikely event that we're *really* still on the UI thread by
    // this point...
    return thumbnails.OrderByDescending(t => t.ImageDateTime).ToList();           
}

请注意,我假设所有异步方法都是合理编写的,例如GetAllDirectoriesWithImageAsync 在返回任务之前不会执行大量同步工作。

关于c# - 为什么带有 await 关键字的异步方法仍然阻塞主线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43841542/

相关文章:

c# - 闭包中的 Foreach 变量。为什么这些片段的结果不同?

c# - 获取 XML 文件的版本而不从服务器下载它

c# - .NET 标准库是否支持 EF Core 添加迁移?

c# - System.UnauthorizedAccessException : Access is denied. Windows Phone 使用文件时

c# - 如何模拟返回 Task<IList<>> 的方法?

c# - DotNetZip 取消任务中的提取

c# - .msg 文件给出下载错误

c# - ASP.NET 中的 XML POST 和解析

c# - 等待空传播 System.NullReferenceException

javascript - express router 不能等待一个 promise 来解析吗?