【问题标题】:C# async awaitable clarification?C#异步等待澄清?
【发布时间】:2013-06-27 03:12:45
【问题描述】:

我读过here

Await 检查 awaitable 是否已已经完成;如果 awaitable 已经完成,然后该方法继续 运行(同步,就像常规方法一样)。

什么?

当然它不会完成,因为它甚至还没有开始!

示例:

public async Task DoSomethingAsync()
{ 
  await DoSomething();
}

await 在这里检查 awaitable 是否已经完成 (根据文章),但是它(DoSomething)还没有事件开始了! ,因此结果将始终false

如果文章是这样说的,那就有道理了:

Await 检查 awaitable 以查看它是否已经完成 在x 毫秒内; (超时)

我可能在这里遗漏了一些东西..

【问题讨论】:

  • 您一直说等待的“尚未开始”,但这只是您问题中的断言/假设,而不是您可以在任何文档中指出的内容。

标签: c# .net-4.5 async-await c#-5.0


【解决方案1】:

考虑这个例子:

public async Task<UserProfile> GetProfileAsync(Guid userId)
{
    // First check the cache
    UserProfile cached;
    if (profileCache.TryGetValue(userId, out cached))
    {
        return cached;
    }

    // Nope, we'll have to ask a web service to load it...
    UserProfile profile = await webService.FetchProfileAsync(userId);
    profileCache[userId] = profile;
    return profile;
}

现在想象在另一个异步方法中调用它:

public async Task<...> DoSomething(Guid userId)
{
    // First get the profile...
    UserProfile profile = await GetProfileAsync(userId);
    // Now do something more useful with it...
}

完全有可能GetProfileAsync 返回的任务在方法返回时已经完成 - 因为缓存。当然,或者您可能正在等待异步方法的结果以外的其他内容。

所以不,你声称等待它时等待它不会完成的说法是不正确的。

还有其他原因。考虑这段代码:

public async Task<...> DoTwoThings()
{
    // Start both tasks...
    var firstTask = DoSomethingAsync();
    var secondTask = DoSomethingElseAsync();

    var firstResult = await firstTask;
    var secondResult = await secondTask;
    // Do something with firstResult and secondResult
}

第二个任务可能会在第一个任务之前完成 - 在这种情况下,当您等待第二个任务时,它已经完成,您可以继续进行。

【讨论】:

  • 微软是否对Task&lt;..&gt; 语法感到非常沮丧,以至于他们决定将其编写为糖语法?我的意思是它就像启动任务并检查结果属性...
  • @RoyiNamir:不,真的不是。这是一个很长的路要走。我建议您将我的异步代码放在github.com/jskeet/DemoCode/tree/master/AsyncIntro 并尝试在没有async 的情况下重写它。你会发现它更加痛苦,我向你保证。编译器做了大量工作来删除样板、容易出错的代码。
  • Jon,在您的示例中,您使用了“从 Web 服务下载”——一个可能支持异步方法(例如 beginXXX)的 IO 操作——所以我们不这样做不想在 IO 正在进行时阻塞线程。 但是如果DoSomething 只是一种计算长斐波那契数的方法呢?即使我们打开一个 Task ,它也会浪费 another 线程来进行计算。所以我问,真正的好处是 IO 操作吗?谢谢。
  • @RoyiNamir:对于计算密集型任务,您可能想要创建一个新任务,可能在线程池线程上,例如与Task.Run。在完成后返回 UI 线程方面仍然有一个好处。
【解决方案2】:

await 可以接受任何TaskTask&lt;T&gt;包括已完成的任务

在您的示例中,内部 DoSomething() 方法(应该命名为 DoSomethingAsync(),其调用者 DoSomethingElseAsync())返回 Task(或 Task&lt;T&gt;)。该任务可以是从其他地方获取的已完成任务,该方法不需要启动它自己的任务。

【讨论】:

    猜你喜欢
    • 2014-03-09
    • 2013-06-12
    • 1970-01-01
    • 2017-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-26
    相关资源
    最近更新 更多