6

Suppose you have a method that wraps an inner long-running method. This outer method may do a tiny amount of work before/after calling said long-running method. For example:

public async Task<int> LongRunningWrapperAsync()
{
    int result = await LongRunningAsync();
    result++;
    return result;
}

It seems like the added weight of the boilerplate code generated by using async is not necessarily worth the benefit of using await, since its continuation is basically trivial. Therefore, given a sufficiently trivial* continuation, is it more performant to use Task.ContinueWith? E.g.

public Task<int> LongRunningWrapperAsync()
{
    return LongRunningAsync().ContinueWith(task => task.Result + 1,
                 TaskContinuationOptions.ExecuteSynchronously);
}

* Yes, both 'sufficiently' and 'trivial' are vague terms. Also, I've ignored exception handling in this contrived example. I suppose the need to handle exceptions implies that the continuation is non-trivial.

mztan
  • 305
  • 3
  • 10
  • 1
    Just try it yourself - use `System.Diagnostics.Stopwatch` and execute each code a large number of times. – Knaģis Jan 28 '14 at 10:35
  • 2
    I disagree with the "trivial"ness of your example. `async/await` will wire up Exceptional cases as well as your happy case to your continuation. This allows for much easier development. The point of using libraries and frameworks is often the edge cases around a trivial concept. – Aron Jan 28 '14 at 10:46

1 Answers1

10

Therefore, given a sufficiently trivial* continuation, is it more performant to use Task.ContinueWith?

Yes, but I argue that this is the wrong question to ask.

It is more performant. However, you have to be very careful to handle edge cases (in particular, any exceptions raised by LongRunningAsync would get wrapped in an AggregateException by your code). In addition, await will capture a context by default, and resume the method in that context. You can handle special cases in a more performant way via ContinueWith, but you can't handle the general case in a more performant way.

But performance is the wrong question to ask anyway. I argue that a better question to ask is: Is the code sufficiently performant, and if so, which solution is more maintainable?

Consider how many times the code will be executed. Millions? How much time will be saved? A few nanoseconds? How much developer time with the ContinueWith approach cost? Every time anyone looks at the code, it takes that much longer to see what it's doing. It is a far, far better decision to save developer time by making the code more maintainable (concentrating the savings in your company) than it is to save an absolutely minuscule amount of time when the code is run (spreading the savings across all your clients - and spreading it so thin that no single client will even be aware of it).

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810