Showing posts with label TPL. Show all posts
Showing posts with label TPL. Show all posts

Tuesday, October 10, 2017

Free resources for Parallel Programming

Below is a list of free resources for parallel programming with .NET.

Microsoft's main site for all things parallel

Parallel Programming in the .NET Framework


Parallel Programming with Microsoft .NET: Design Patterns for Decomposition and Coordination on Multicore Architectures.




Thursday, September 21, 2017

Exception handling of Tasks in .NET

Exception Handling rules


Task Parallel Library (TPL) handles exceptions well.

If a task throws an exception E that goes unhandled:

  • task is terminated
  • E is caught, saved as part of an AggregateException AE, and stored in task object's Exception property.
  • AE is re-thrown when one of the following is called: .Wait, .Result, or .WaitAll

Example with no exception handling:

Task<int> t = Task.Factory.StartNew(code);
int r = t.Result;

Simple example with exception handling:


Task<int> t = Task.Factory.StartNew(code);
try { int r = t.Result; }
catch (AggregateException ae) 
{
Console.WriteLine(ae.InnerException.Message);
}

Working with AggregateException graph (preferred way)

The above handling is not really sufficient. When catching the AggregateException it can be an graph of Exceptions connected via the InnerExceptions property. For example, AggregateException.InnerExceptions can contain another AggregateExceptions or Exceptions. We need to look at the leaves of the graph to get the real exceptions of interest. An easy way to do this is to use the Flatten() method;

Task<int> t = Task.Factory.StartNew(code);
try { int r = t.Result; }
catch (AggregateException ae) 
{
ae = ae.Flatten();
foreach (Exception ex in ae.InnerExceptions)
Console.WriteLine(ex.Message);
}


Example of what happens when an exception is NOT "observed"

Task t = Task.Factory.StartNew(() =>
{
int d = 0;
int answer = 100 / d;
}
);

This will cause the application to crash when garbage collection is executed.

Exception handling Design and the need for observing

It is highly recommended that you "observe" all unhandled exceptions so that when the task is garbage-collected the exception will be re-thrown then. Unfortunately, this is not the ideal place to handle the exception.

To observe you can do it by doing one of the following:
  • call .Wait or touch .Result - the exception is re-thrown at this point
  • call Task.WaitAll - the exception(s) are re-thrown when all have finished
  • touch the task's Exception property after the task has completed
  • subscribe to TaskScheduler.UnobservedTaskException which is particularly useful if a third party block of code throws the exception.
NOTE: Task.WaitAny() does NOT observe the exception.

Wait Example

try { t.Wait(); }
catch (AggregateException ae) { ... }

Exception accessed Example

if (t.Exception != null)
{ ... }

Result accessed Example

try { var r = t.Result; }
catch (AggregateException ae) { ... }

Last resort exception handling

If you don't "observe" an exception you can still handle it by subscribing to the TaskScheduler.UnobservedTaskException. 

Use cases for using this method:

  • speculative tasks that you don't cancel and don't really care about the result once you get one result. If one of those tasks throws an exception you don't want it to be thrown when garbage collection takes place.
  • Using a third party library that you don't trust and don't know if it will throw any exceptions.
You only want to subscribe once to the event. Good places to do this are in the application startup code, a static constructor, etc.

How to subscribe:

TaskScheduler.UnobservedTaskException += new EventHandler<UnobservedTaskExceptionEventArgs>(MyErrorHandler);

Example handling the error

static void MyErrorHandler(object sender, UnobservedTaskExcpetionEventArgs e)
{
Console.WriteLine($"Unobserved error:{e.Exception.Message}");
e.SetObserved();
}

Note the call to e.SetObserved(). This is what tells .NET that we have observed the Exception and now it will not be thrown at garbage collection. 

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.