【问题标题】:Difference between returning and awaiting a Task in an async method [duplicate]在异步方法中返回和等待任务之间的区别[重复]
【发布时间】:2014-06-08 19:55:01
【问题描述】:

下面的方法有什么区别吗?一个比另一个更可取吗?

public static async Task SendAsync1(string to, string subject, string htmlBody) {
  // ...
  await smtp.SendMailAsync(message);
  // No return statement
}

public static Task SendAsync2(string to, string subject, string htmlBody) {
  // ...
  return smtp.SendMailAsync(message);
}

这个方法将从 MVC 控制器方法中调用;例如:

public async Task<ActionResult> RegisterUser(RegisterViewModel model)
{
  // ...
  await Mailer.SendAsync(user.Email, subject, body);
  return View(model);
}

【问题讨论】:

  • 如果使用 SendAsync1,可能会在 2 个地方维护状态(通过 async/await 状态机制)的成本,但也许 async/await 状态机足够聪明,可以优化它...只是一个想法,但它很有趣。

标签: c# .net task-parallel-library async-await


【解决方案1】:

有两个实际区别:

  1. 第二个选项不会创建允许async-await 使用的状态机机制。这将对性能产生次要的积极影响。
  2. 异常处理会有些不同。当您将方法标记为async 时,任何异常都存储在返回的任务中(来自异步部分和同步部分),并且仅在等待(或等待)任务时抛出。当不是async 时,同步部分的异常就像在任何其他方法中一样。

我的建议:使用第二个来提高性能,但要注意异常和错误。


显示差异的示例:

public static async Task Test()
{
    Task pending = Task.FromResult(true);
    try
    {
        pending = SendAsync1();
    }
    catch (Exception)
    {
        Console.WriteLine("1-sync");
    }

    try
    {
        await pending;
    }
    catch (Exception)
    {
        Console.WriteLine("1-async");
    }

    pending = Task.FromResult(true);
    try
    {
        pending = SendAsync2();
    }
    catch (Exception)
    {
        Console.WriteLine("2-sync");
    }

    try
    {
        await pending;
    }
    catch (Exception)
    {
        Console.WriteLine("2-async");
    }
}

public static async Task SendAsync1()
{
    throw new Exception("Sync Exception");
    await Task.Delay(10);
}

public static Task SendAsync2()
{
    throw new Exception("Sync Exception");
    return Task.Delay(10);
}

输出:

1-async
2-sync

【讨论】:

  • “不会创建状态机机制” - 这是什么意思?你怎么知道,在哪里可以看到?它就像隐形湖中的隐形人,我根本无法理解:(我的意思是物理上 - 发生了什么?
  • @monstro sharplab.io/…
【解决方案2】:

首先,我认为您的示例中的代码无法编译。您需要从 SendAsync2 中删除“async”关键字。

如果你这样做,那么这些方法可以互换使用,所以不,在这种情况下没有区别。我更喜欢没有 async/await 的那个。

但是,有些情况下似乎没有区别,但区别在于细节。例如,考虑以下代码:

async Task<X> Get() 
{
     using (something) 
     {
          return await GetX();
     }
}

如果您将其更改为:

Task<X> Get() 
{
    using (something)
    {
        return GetX(); 
    }
}

然后using 块不再保护封装在 x 中的执行,并且something 将比第一种情况更早地被释放。例如当something 是实体框架上下文时很重要。

return awaittry 块内也是如此。

【讨论】:

  • 使用/try-catch 观察潜在的陷阱周围!
【解决方案3】:

你的第一个方法awaits 将导致编译器创建一个状态机,因为一旦the await 关键字被命中,该方法将返回给调用者,一旦等待的部分完成,它必须从点它停止的地方。

但是,由于您在等待后什么都不做(没有继续),所以不需要那个状态机。

在这种情况下首选第二种方法,您可以省略其中的 async 关键字,因为您没有等待任何内容

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-01
    • 1970-01-01
    • 2021-11-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多