任务和异步任务的区别 [英] Difference between Task and async Task
问题描述
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 theasync
method in the same "context". This "context" isSynchronizationContext.Current
unless it isnull
, in which case it isTaskScheduler.Current
. This means that if you callMyAsync
on a UI thread (or within an ASP.NET request context), thenMyContinuation
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 upTaskScheduler.Current
, which can cause surprising behavior. I describe this problem in detail on my blog. That post is aboutStartNew
; butContinueWith
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 inContinueWith
. For example, it usesDenyChildAttach
(to ensure asynchronous tasks are not mistakenly used as parallel tasks) andExecuteSynchronously
(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屋!