Pages

Monday, September 7, 2015

ContinueWith Vs await

TPL is new library introduced in C # 4.0 version to provide good control over thread, to make use of multicore CPU by mean of parallel execution on thread. Below discussion is not about TPL but its about ContinueWith function available on Task Class of TPL and await keyword introduced in C# 5.0 to support asynchronous calls.

ContinueWith - its method available on the task which allows executing code after task finished execution. In simple word it allows continuation.

Things to note here is ContinueWith also return one Task. That means you can attach ContinueWith on task return by this method.

In above code new created task runs LongRunningOperation and once task execution completed ContinueWith execute operation on retuned task and print result of task.

ContinueWith operation thask get executed by default thread scheduler, one can also provide other scheduler for running task on it, this discussed in later in this article.

Note: below code is LongRunningOperation called by task. LongRunningOpertion here is just example in real program one cannot call long running operation on task, and if one want to call longrunning task than one need to pass TaskCreationOperation.LongRunning.

await – its keyword that cause runtime to run operation on new task and cause executing thread to return and continue with execution (In most of the cases executing that is main thread of application). Once await operation get finished it returns to statement where is left of (i.e. returns to caller i.e. it returns according state saved) and start executing statements.

So await wait for newly created task to finish and ensures continuation once execution of waiting task is finished.

await keyword used with async to achieve asynchronous programming in C#. It’s called asynchronous programming because runtime capture state of program when it encounter await keyword (which is similar to yield in iterator) and restore state back once waited task finish so the continuation runs on correct context.

In above example new created task calls LongRunningOperation and execution left of once main thread encounter await keyword i.e. main thread return to caller of AsyncOpetion and execute further. Once LongRunningOpertaion completed than result of task get printed on console.

So here because state saved when await encountered flow returns on same context one operation on task executed.

Note: State is having detail about executioncontext/synchronizationcontext.

So form above its clear that both Task.ContinueWith and await Task wait for task to finish and allows continuation after task completion. But both works differently.

Difference between ContinueWith and await

Saving Sate for And return on Execution context
ContinueWith doesn’t save any kind of state, continuation operation attached using ContinueWith run on default thread scheduler in case not scheduler provided.

await – on encounter of this keyword state get saved and once task on which await done get completed execution flow pick up saved state data and start execution statement after await. (Note: State is having detail about executioncontext/synchronizationcontext.)

Posting Completed Task result on UI Control
Below is example with ContinueWith and await to display completion task result on UI control.

ContinueWith :

Consider below code which display result of completed task on UI label.

This exception occurs because Continuation operation UpdateUI operation runs on different thread, in this case thread will be provided by default threadschedular which is ThreadPool and it doesn’t have any information about Synchronization context on which to run.

Code written with await doesn’t throw any exception when posting data to UI control, No special code required for await. This happens because as discussed in 1 point of difference , on encounter of await state data get saved which has information about SynchronizationContext.

So if one need to post data on UI than await is good option because there is no need of extra care/code to post data on UI.

Above function calculate factorial of number and return KeyValuePair to caller to display calculation.

Now problem statement is above function to calculate factorial of number 1 to 5.

ContinueWith

Below is code to calculate factorial of numbers between 1 to 5. Expectation from the code below is calculating factorial of number, display it in order and once it completed “Done” message will get printed on the console.

Once code get executed one will find that “Done” message get printed immediately i.e. first than factorial of number get displayed on screen. One more problem is number factorial is not get displayed in order. Below is output of the code execution.

So to resolve problem with above code , code need to be refactored like this

In above code to maintain sequence, task need to be fired one by one. And for that once one task completes its execution Contuation on it with the help of ContinueWith method call function again. It’s like doing recursive calling to function.

And to display “Done” message at the end need to check for the seed to function. Which checks seed value increases 6 or not.

But now there is need for attaching continuation on completion of FactContinueWithSeq, to achieve this code need to be done as below.

In above code TaskCompletionSource is used to achieve the code of providing continutation on completion of factorial calculation.

So one need to do lot of code for providing expected result, which is calculating factorial in sequence, waiting on calculation and once calculation get completed “Done” message get printed on console.

Above code is simple and clean there is no need of doing whole big refactoration which required when doing same thing with ContinueWith.

Summary

From above difference/comparison of ContinueWith vs await it clear that in many scenario using and await is very helpful.
But there is also scenario where more complex things not required with proper error/cancellation handling in that case continuewith is helpful. But this scenario is very rare.

It’s always good to go with simple, easy and clear solution, for this my suggestion is always go with await rather than ContinueWith.