【问题标题】:Difference between Task and async Task任务和异步任务之间的区别
【发布时间】:2014-04-10 19:41:13
【问题描述】:

C# 提供了两种创建异步方法的方式:

Task():

static Task<string> MyAsyncTPL() {
  Task<string> result = PerformWork();
  return result.ContinueWith(t => MyContinuation());
}

async Task():

static async Task<string> MyAsync() {
  string result = await PerformWork();
  return MyContinuation();
}

以上两种方法都是async,实现相同的目的。那么,我什么时候应该选择一种方法而不是另一种方法?使用其中一种是否有任何指导方针或优势?

【问题讨论】:

  • 您的示例不一样 - 如果从 PerformWork 返回的任务失败或被取消,它们的行为会有所不同。
  • 或者如果有一个当前的SynchronizationContext。或者如果返回的任务被用作父任务。或者可能是await 比ContinueWith 处理得更体面的其他一些晦涩的角落案例。

标签: c# .net asynchronous task


【解决方案1】:

我建议您使用await 而不是ContinueWith。虽然 - 在较高级别 - 它们非常相似,但它们也具有不同的默认行为。

当您使用ContinueWith 时,您选择的是较低级别的抽象。特别是,这里有一些“危险点”,这就是为什么我不建议使用ContinueWith,除非方法真的很简单(或者你的名字是Stephen Toub):

  • async Task 方法引发的异常被放置在返回的任务上;由非async 方法引发的异常会直接传播。
  • await 默认将在相同的“上下文”中恢复 async 方法。这个“上下文”是SynchronizationContext.Current,除非它是null,在这种情况下它是TaskScheduler.Current。这意味着如果您在 UI 线程(或在 ASP.NET 请求上下文中)调用 MyAsync,那么 MyContinuation 也将在 UI 线程(或在同一个 ASP.NET 请求上下文中)执行。这个我再解释一下on my blog。
  • 您应该始终为ContinueWith 指定调度程序;否则,它将获取TaskScheduler.Current,这可能会导致令人惊讶的行为。我详细描述了这个问题on my blog。那篇文章是关于StartNew;但ContinueWith 与该帖子中描述的“非默认默认调度程序”问题相同。
  • await 使用ContinueWith 默认情况下未设置的适当行为和优化标志。例如,它使用DenyChildAttach(以确保异步任务不会被错误地用作并行任务)和ExecuteSynchronously(一种优化)。

简而言之,将ContinueWith 用于异步任务的唯一原因是为了节省非常少量的时间和内存(通过避免async 状态机开销),并且作为交换您的代码可读性和可维护性较差。

举一个非常简单的例子,你可能会侥幸成功;但正如 Jon Skeet 指出的那样,一旦你有了循环,ContinueWith 代码就会变得复杂起来。

【讨论】:

    【解决方案2】:

    await 基本上是延续的简写,默认情况下,延续使用相同的同步上下文。

    对于像您这样的非常简单的示例,使用 await 并没有太多好处 - 尽管异常的包装和展开使方法更加一致。

    但是,当您有更复杂的代码时,async 会产生巨大 的不同。想象一下你想要的:

    static async Task<List<string>> MyAsync() {
        List<string> results = new List<string>();
        // One at a time, but each asynchronously...
        for (int i = 0; i < 10; i++) {
            // Or use LINQ, with rather a lot of care :)
            results.Add(await SomeMethodReturningString(i));
        }
        return results;
    }
    

    ... 手动延续会变得更加麻烦。

    此外,async/await 可以与 Task/Task&lt;T&gt; 以外的类型一起使用,只要它们实现了适当的模式。

    值得阅读更多关于它在幕后所做的事情。您可能想从MSDN 开始。

    【讨论】:

      猜你喜欢
      • 2011-03-16
      • 2015-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多