Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

C# provides two ways of creating asynchronous methods:

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();
}

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
203 views
Welcome To Ask or Share your Answers For Others

1 Answer

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

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):

  • 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).

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.

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...