任务和异步任务的区别 [英] Difference between Task and async Task

查看:25
本文介绍了任务和异步任务的区别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

C# provides two ways of creating asynchronous methods:

Task():

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,实现的效果是一样的.那么,我什么时候应该选择一种方法而不是另一种方法?使用其中一种方法有什么指导方针或优势吗?

Both of the above methods are async and achieve the same thing. So, when should I choose one method over the other? Are there any guidelines or advantages of using one over the other?

推荐答案

我建议您使用 await 而不是 ContinueWith.虽然 - 在高层次上 - 它们非常相似,但它们也有不同的默认行为.

I recommend you use await rather than ContinueWith. While - at a high level - they are very similar, they also have different default behavior.

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

When you use ContinueWith, you are choosing a lower-level abstraction. In particular, here are some "danger points", and this is why I don't recommend using ContinueWith unless the method is really simple (or your name is Stephen Toub):

  • async Task 方法引发的异常被放置在返回的任务上;从非async 方法引发的异常直接传播.
  • await 默认会在相同的上下文"中恢复 async 方法.这个上下文"是SynchronizationContext.Current,除非它是null,在这种情况下它是TaskScheduler.Current.这意味着如果您在 UI 线程上(或在 ASP.NET 请求上下文中)调用 MyAsync,则 MyContinuation 也将在 UI 线程上(或在同一线程中)执行ASP.NET 请求上下文).我在在我的博客上详细解释了这一点.
  • 你应该总是为 ContinueWith 指定一个调度程序;否则,它会选择 TaskScheduler.Current,这会导致令人惊讶的行为.我在在我的博客上详细描述了这个问题.那篇文章是关于StartNew;但是 ContinueWith 具有该帖子中描述的相同非默认默认调度程序"问题.
  • await 使用在 ContinueWith 中默认未设置的适当行为和优化标志.例如,它使用 DenyChildAttach(确保异步任务不会被错误地用作并行任务)和 ExecuteSynchronously(一种优化).
  • Exceptions raised from async Task methods are placed on the returned task; exceptions raised from non-async methods are propagated directly.
  • await will by default will resume the async method in the same "context". This "context" is SynchronizationContext.Current unless it is null, in which case it is TaskScheduler.Current. This means that if you call MyAsync on a UI thread (or within an ASP.NET request context), then MyContinuation will also execute on the UI thread (or in that same ASP.NET request context). I explain this more on my blog.
  • You should always specify a scheduler for ContinueWith; otherwise, it will pick up TaskScheduler.Current, which can cause surprising behavior. I describe this problem in detail on my blog. That post is about StartNew; but ContinueWith has the same "non-default default scheduler" problem described in that post.
  • await uses appropriate behavior and optimization flags that are not set by default in ContinueWith. For example, it uses DenyChildAttach (to ensure asynchronous tasks are not mistakenly used as parallel tasks) and ExecuteSynchronously (an optimization).

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

In short, the only reason to use ContinueWith for asynchronous tasks is to save an extremely small amount of time and memory (by avoiding the async state machine overhead), and in exchange your code is less readable and maintainable.

举一个非常简单的例子,你可能会侥幸逃脱;但正如 Jon Skeet 指出的那样,一旦你有了循环,ContinueWith 代码的复杂性就会爆炸.

With an extremely simple example, you might get away with it; but as Jon Skeet pointed out, as soon as you have loops the ContinueWith code simply explodes in complexity.

这篇关于任务和异步任务的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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