为什么带有await关键字的异步方法仍然阻塞主线程? [英] Why is an async method with await keyword still blocking the main thread?

查看:1006
本文介绍了为什么带有await关键字的异步方法仍然阻塞主线程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Can anyone explain to me the difference between these 2 async methods?

方法A

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

方法B

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

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

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

To my understanding both methods should return to the caller and does not block the UI thread, but in this case only Method A works as expected while Method B blocks my UI.

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

I believe there must be some fundamental concept that I may have misunderstood in the usage of async/await.

有人可以启发我吗?

推荐答案

方法A基本上是在单独的任务中执行一切,这很可能会在新线程中结束.当您等待任务完成时,您将不会阻止任何操作.

Method A is basically executing everything in a separate task, which will probably end up in a new thread. When you await the resulting task, you won't block anything.

方法B通过调用GetAllDirectoriesWithImageAsync开始,并等待结果.这意味着在处理异步操作时,您不会阻塞UI线程-但是默认情况下,当您等待任务时,这意味着延续将在UI线程中运行.因此imageUris.Select(...).OrderByDescending(...).ToList()将在UI线程中运行,我怀疑那是导致UI出现问题的部分.

Method B starts by calling GetAllDirectoriesWithImageAsync, and awaits the result. That means while the asynchronous operation is processing, you won't be blocking the UI thread - but by default, when you await the task, that means the continuation will run in the UI thread. So the imageUris.Select(...).OrderByDescending(...).ToList() will run in the UI thread, and I suspect that's the part that's causing problems in the UI.

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

Now you could call .ConfigureAwait(false) at the end of the first line of GetAllThumbnailsAsync, to indicate that you don't need to execute the second part on the UI thread - but that wouldn't guarantee that you wouldn't execute the second part on the UI thread. Instead, it seems to me that you really want an asynchonous way of getting thumbnails. Then you could do something like:

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在返回任务之前不会执行大量同步工作.

Note that I'm assuming that all async methods are written reasonably, e.g. that GetAllDirectoriesWithImageAsync doesn't perform a significant amount of synchronous work before returning a task.

这篇关于为什么带有await关键字的异步方法仍然阻塞主线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆