Showing posts with label Async. Show all posts
Showing posts with label Async. Show all posts

Friday, January 26, 2018

Blocking

Task.Delay()

If you are in an async method and you want to have it wait for a period of time before continuing your first thought might be to use Thread.Sleep(), but this would work the way you may think. Task.Delay() is what you want to use. Sleep just sleeps on the current thread which is the same as the thread that is calling the async method. Having an async method does NOT create threads unless the

Task.Run()

Task.Run() method is used to run a non-async method on another thread (from the thread pool by default). This is essentially just a background thread and has nothing to do with async. However since Task.Run() returns a Task you can await the result. This makes tracking the task and getting the result very easy.

Task.Run() is a good way to run a non-async method from an async method. There is overhead of spinning up an additional thread just to run this non-async code and then we would await the completion of the thread. This overhead is sometimes the only option if there is no async method available to call and all you have is a non-async method to call and you don't have access to change it.



Monday, October 16, 2017

Async in C#

Tips

A thread is a relatively heavy weight structure. 1 thread takes 1M of Stack Space. A task is NOT a thread. You can have multiple tasks running on a single thread (such as UI thread).

Task.Delay() is like Thread.Sleep(), but it is a Task that won't complete for a specified amount of time.

The keyword async is not part of the method signature. For example, it doesn't show up in interfaces. It is convention to add Async to the end of a method name though. This tell the reader it is async.

Return Task, not void.

await

Frees thread to do other things such as update UI, etc. Before await is called the stack trace is in the method you called it from which makes sense. The potentially surprising thing is that the line after the await does NOT have the same stack trace. It is now in the same thread, but clearly not in the same calling method anymore. This is because the compiler creates a state machine when the code is complied. It's building what would have been done by hand before we had the keyword await in C#.
  • await frees a thread while we wait for an operation to complete. For example, handle another request in web scenario, update UI thread in desktop scenario. 
  • It does NOT block the thread, it actually frees the thread to do something else. 
  • The execution is stopped until the task is complete. 
  • When the task is complete the thread gets focus and execution continues. This is similar in concept to a callback after something is complete.

Exception Handling

If there is an exception in an async method it will be thrown and can be caught as if it was not an async method. For example, a simple try-catch.

Tuesday, September 12, 2017

Waiting for a task to finish and harvesting Result in .NET 4

The below techniques work for code tasks and facade tasks.

Explicitly Waiting for a single task

Sometime when working with task you need to wait for a computation to complete before you can do something with the result (such as write it to the screen) as shown below.

Task t = Task.Factory.StartNew( /* code */ );
t.Wait();
Console.WriteLine(t.Status);

The result would be one of the following:
  • RanToCompletion
  • Canceled
  • Faulted

Explicitly Waiting for Multiple tasks (Ordered)

decimal min = 0;
decimal max = 0;
Task t_min = Task.Factory.StartNew(() => {min = data.Price.Min();});
Task t_max = Task.Factory.StartNew(() => {max = data.Price.Max();});

t_min.Wait();
t_max.Wait();

Console.WriteLine(min);
Console.WriteLine(max);

Note: You can use Wait() any task as well if they are dependent on each other. This reduces the benefits of parallelism.

Harvesting Result (Implicitly Waiting for Multiple tasks Sequentially)

While there is nothing wrong with explicitly waiting there is a cleaner way to do it and with less code code.

Task<decimal> t_min = Task.Factory.StartNew(() => {return data.Price.Min();});
Task<decimal> t_max = Task.Factory.StartNew(() => {return data.Price.Max();});

Console.WriteLine(t_min.Result);
Console.WriteLine(t_max.Result);

Notice no variables that could have a race condition if more than one task was accessing one of them. Notice no calls to Wait() because Result implicitly calls Wait() before it returns the value.

Explicitly Waiting for All tasks to complete

The above waiting scenario implies that the order that we wait for the tasks to finish matters. If it does not matter and we want to wait for all tasks to complete before continuing then semantically it is better to use WaitAll().

Here is the same code as above, but instead using a WaitAll();

Task<decimal> t_min = Task.Factory.StartNew(() => {return data.Price.Min();});
Task<decimal> t_max = Task.Factory.StartNew(() => {return data.Price.Max();});

Task.WaitAll(new Task[] {t_min, t_max});
Console.WriteLine(t_min.Result);
Console.WriteLine(t_max.Result);

Explicitly Waiting for ANY task to complete

There are scenarios searches that are returning the first response and displaying it and ignoring the other responses that make sense. In this scenario, we don't care which one is first, but we do want to wait for one to complete.

Here is a new example using WaitAny(). It takes a list of tasks as input and returns the index in that array that finished first. That index can be used to get the results of the task that completed first as shown below.

Task<string> t_msn = Task.Factory.StartNew(() => {return SearchMsn;});
Task<string> t_google = Task.Factory.StartNew(() => {return SearchGoogle();});

Task[] tasks = new Task[] {t_msn, t_google};
int firstIndex = Task.WaitAny(tasks);
Task firstTask = tasks[firstIndex];
Console.WriteLine(firstTask.Result);

WaitAllOneByOne pattern

There are scenarios where you want to wait for all tasks to finish, but process results as each one completes. Another way to think of this is, imagine we want to start several tasks and we don't know in what order they will complete, but we want to process them as they are finished. This assumes that we don't need to wait for them all before we start processing the results.

This pattern is useful when:
  • Some tasks may fail - discard / retry
  • Overlap computations with result processing - aka hide latency
There is no built in feature for this and this is more of a pattern that you can implement if this is your scenario. Here is one conceptual implementation.

while (tasks.Count > 0)
{
int taskIndex = Task.WaitAny(tasks.ToArray());

// check and observe exception and ignore it
if (tasks[taskIndex].Exception == null)
{
// process tasks using tasks[taskIndex].Result;
}

tasks.RemoveAt(taskIndex);
}

// if we get here all tasks failed. Act accordingly

Notice this is NOT a tight while loop that will spin while the tasks are processing. The Task.WaitAny() blocks execution of the while loop until a task completes then in loops again and starts another Task.WaitAny() and continues this until all tasks have been processed.

Task Composition (One-to-One)

Sometimes we want the completion of one task to trigger the start of another task. This can be done as noted before using simple Wait() in the second task. This is the TPL approach to Wait().

That might look like this

Task t1 = Task.Factory.StartNew(() => { /* code here */ });
Task t2 = Task.Factory.StartNew(() => { t1.Wait(); /* more code here */ });

The above implementation will work, however t2 actually starts BEFORE t1 is finished. This is probably reasonable if we remember to do a t1.Wait() first thing in the code of t2. From an orchestration perspective and responsibility point of view t2 should not be concerned with waiting for t1. This should be at a higher level. This will make testing the code for t2 much easier.

To fill the deficiencies noted above we can use the ContinueWith() method wait to start t2 until after t1 has finished. One added benefit is this allows .NET to optimize the scheduling such that both t1 and t2 would be on the same thread and could actually optimize away the wait.

That code might look like this.

Task t1 = Task.Factory.StartNew(() => { /* code here */ });
Task t2 = T1.ContinueWith((antecedent) => { /* more code here */ });

Note, the parameter antecedent references the task that just finished. This can be used to check the status of the task (t1 in this case), get the result, etc.

For example to get the result from t1 the above code would be changed to look like this:

Task t1 = Task.Factory.StartNew(() => { /* code here */ });
Task t2 = T1.ContinueWith((antecedent) => { var result = antecedent.Result; /* more code here */ });

Task Composition (Many-to-one)

TPL has alternatives for WaitAll() and WaitAny() also. Instead of using WaitAll() and WaitAny(), you can use ContinueWhenAll() and ContinueWhenAny respectvely.

ContinueWhenAll

Using our example for WaitAll() we had:

Task<decimal> t_min = Task.Factory.StartNew(() => {return data.Price.Min();});
Task<decimal> t_max = Task.Factory.StartNew(() => {return data.Price.Max();});

Task.WaitAll(new Task[] {t_min, t_max});
Console.WriteLine(t_min.Result);
Console.WriteLine(t_max.Result);

We could convert that to use ContinueWhenAll() as follows:

Task<decimal> t_min = Task.Factory.StartNew(() => {return data.Price.Min();});
Task<decimal> t_max = Task.Factory.StartNew(() => {return data.Price.Max();});

Task[] tasks = new Task[] {t_min, t_max};

Task.Factory.ContinueWhenAll(tasks, (setOfTasks) => 
{
Console.WriteLine(t_min.Result);
Console.WriteLine(t_max.Result);
});

ContinueWhenAny

Using our example for WaitAny() we had:

Task<string> t_msn = Task.Factory.StartNew(() => {return SearchMsn;});
Task<string> t_google = Task.Factory.StartNew(() => {return SearchGoogle();});

Task[] tasks = new Task[] {t_msn, t_google};
int firstIndex = Task.WaitAny(tasks);
Task firstTask = tasks[firstIndex];
Console.WriteLine(firstTask.Result);

We can convert that to use ContinueWhenAny() as follows:

Task<string> t_msn = Task.Factory.StartNew(() => {return SearchMsn;});
Task<string> t_google = Task.Factory.StartNew(() => {return SearchGoogle();});

Task[] tasks = new Task[] {t_msn, t_google};

Task.Factory.ContinueWhenAny(tasks, (firstTask) =>
{
Console.WriteLine(firstTask.Result);
}

The code is similar to using WaitAll() and WaitAny(), but again a bit easier to test because the responsibility of the orchestration is at a higher level. It also reduces a few lines of code.

Reference

Content is based on Pluralsight video called Introduction to Async and Parallel Programming in .NET 4 by Dr. Joe Hummel. 

Monday, September 11, 2017

Basic overview of Tasks and Task-based Programming in .NET 4+

What and Why

Async Programming - hide latency of potentially long-running or blocking operations (i.e. I/O) by starting them in the background.

Parallel Programming - reduce time of CPU-bound computations by dividing workload & executing simultaneously.

Here we are talking about Tasks and Task Parallel Library (TPL) which gives us:
  • Cancelling
  • Easier Exception Handling
  • Higher-level constructs
  • ...

NOTE: Before this we had
  • Threads
  • Async Programming Model (i.e. async delegate invocation)
  • Event-based Async Pattern (i.e. BrackgroundWorker class)
  • QueueUserWorkItem

Async / Parallel Components of .NET 4

Task Parallel Library (TPL) - library of functions for tasks and the notion of a task
Task Scheduler - responsible for mapping tasks to available worker threads
Resource Manager - manages pool of worker threads
Parallel LINQ (PLINQ) - like link, but runs in Parallel
Concurrent Data Structures - queue, bag, dictionary

Use Cases

Interactive UI
In the UI if there is a non-async chunk of code executing in the UI thread then while the computation is running the UI will be unresponsive. For example you can't drag the window properly or click any other buttons, etc.

Processing requests in parallel such as a website or doing independent computations.

Creating a task

using System.Threading.Tasks;
Task t = new Task( code );
t.Start();

code = computation to perform
Start() = tells .NET that task *can* start, then returns immediately. The program "forks" and now there are two code streams that are executing concurrently (original and T).

Task

A task = object representing an ongoing computation
Provides:

  • Check status
  • wait
  • harvest results
  • store exceptions
Think of a task as an object having the following properties
  • Status
  • Result
  • Exception

Types of Tasks

Code Tasks

Executes given operation.
Example: 
Task t1 = Task.Factory.StartNew(() => { /* code */});

Facade Tasks

Task over existing operation. You use a facade task to provide a common API to the different task technologies that have been used over the years. So, instead of rewriting existing async code you can still benefit from the higher level constructs of a Task based api.
Example: 
var op = new TaskCompletionSource<T>();
Task t2 = op.Task;

Execution model

  • Code-based tasks are executed by a thread on some processor
  • Thread is dedicated to task until task completes.
  • If there is only one core then the threads share the core. This has extra overhead, but allows UI and tasks to be running concurrently. UI isn't intensive so not a problem sharing on thread and switching between the two of them. 
  • Ideally there are multiple cores and each task runs on a different core such that they are running concurrently and in parallel with less overhead.

Actions

When you create a new Task object one of the signatures accepts an Action as the parameter. An easy way to pass your chunk of code as an Action is with a Lambda expression as shown below.

Task t = new Task( () => { many lines of code here} );
t.Start();

Equivalent, but slightly more efficient way of creating the task and starting it in one line:

Task t = Task.Factory.StartNew( () => { many lines of code here } );

The multiple lines of of code will now execute in a background thread.

Reference

Content is based on Pluralsight video called Introduction to Async and Parallel Programming in .NET 4 by Dr. Joe Hummel.