Parallel Class |
Namespace: DigitalRune.Threading
The Parallel type exposes the following members.
Name | Description | |
---|---|---|
Do(Action) |
Executes the given work items potentially in parallel with each other.
This method will block until all work is completed.
| |
Do(IWork) |
Executes the given work items potentially in parallel with each other.
This method will block until all work is completed.
| |
Do(Action, Action) |
Executes the given work items potentially in parallel with each other.
This method will block until all work is completed.
| |
Do(IWork, IWork) |
Executes the given work items potentially in parallel with each other.
This method will block until all work is completed.
| |
For(Int32, Int32, ActionInt32) |
Executes a for loop where each iteration can potentially occur in parallel with others.
| |
For(Int32, Int32, ActionInt32, Int32) |
Executes a for loop where each iteration can potentially occur in parallel with others.
| |
ForEachT |
Executes a for-each loop where each iteration can potentially occur in parallel with others.
| |
RunCallbacks |
Executes all task callbacks on a single thread.
| |
Start(Action) |
Creates and starts a task to execute the given work.
| |
Start(IWork) |
Creates and starts a task to execute the given work.
| |
Start(Action, WorkOptions) |
Creates and starts a task to execute the given work.
| |
Start(Action, Action) |
Creates and starts a task to execute the given work.
| |
Start(IWork, Action) |
Creates and starts a task to execute the given work.
| |
Start(Action, WorkOptions, Action) |
Creates and starts a task to execute the given work.
| |
StartT(FuncT) |
Creates and starts a task which executes the given function and stores the result for later
retrieval.
| |
StartT(FuncT, WorkOptions) |
Creates an starts a task which executes the given function and stores the result for later
retrieval.
| |
StartT(FuncT, Action) |
Creates and starts a task which executes the given function and stores the result for later
retrieval.
| |
StartT(FuncT, WorkOptions, Action) |
Creates and starts a task which executes the given function and stores the result for later
retrieval.
| |
StartBackground(Action) |
Starts a task in a secondary worker thread. Intended for long running, blocking work such as
I/O.
| |
StartBackground(IWork) |
Starts a task in a secondary worker thread. Intended for long running, blocking work such as
I/O.
| |
StartBackground(Action, Action) |
Starts a task in a secondary worker thread. Intended for long running, blocking, work
such as I/O.
| |
StartBackground(IWork, Action) |
Starts a task in a secondary worker thread. Intended for long running, blocking work such as
I/O.
|
Name | Description | |
---|---|---|
ProcessorAffinity |
Gets or sets the processor affinity of the worker threads.
| |
Scheduler |
Gets or sets the task scheduler.
|
The namespace DigitalRune.Threading and the class Parallel provides support for concurrency to run multiple tasks in parallel and automatically balance work across all available processors. The implementation is a replacement for Microsoft's Task Parallel Library (see Task Parallelism (Task Parallel Library)) which is not yet supported by the .NET Compact Framework. This class Parallel provides a lightweight and cross-platform implementation (supported on Windows, Silverlight, Windows Phone 7, and Xbox 360).
The API has similarities to Microsoft's Task Parallel Library, but it is not identical. The names in the namespace DigitalRune.Threading conflict with the types of the namespace System.Threading.Tasks. This is on purpose as only one solution for concurrency should be used in an application. The library has been optimized for the .NET Compact Framework: Only the absolute minimum of memory is allocated at runtime.
The DigitalRune libraries, such as DigitalRune Geometry and DigitalRune Physics, /// make extensive use of the class Parallel. We highly recommend, that if you need support for multithreading in your application, you should take advantage of this class. (Using different solutions for concurrency can reduce performance.)
Tasks:
A task is an asynchronous operation which is started, for example, by calling
Start(Action). This method returns a handle of type Task.
This handle can be used to query the status of the asynchronous operation (see
IsComplete). The method Wait can be called to wait until
the operation has completed.
Futures (Task<T>):
A future is an asynchronous operation that returns a value. A future is created, for example,
by calling StartT(FuncT) and specifying a function that computes a
value. The method returns a handle of type TaskT, which is similar to
Task. The result of a future can be queried by calling
GetResult. Note that GetResult can only be called
once - the handle becomes invalid after the first call!
Background Tasks:
Long running operations which may block (i.e. wait for I/O operation to finish) should be
scheduled as background tasks. Background tasks are created by using the method
StartBackground(Action) (or one of its overloads). Background tasks will
not be scheduled using the Scheduler (see below). Instead the class
Parallel manages an additional pool of threads that are used for background
tasks. The processor affinity of these threads is not set automatically. The background tasks
will usually run on the same hardware thread where the background thread was created first or
run last. The processor affinity can be set manually from within the task by calling
Thread.SetProcessorAffinity.
Exception Handling:
The tasks executed asynchronously can raise exceptions. The exceptions are stored internally
and a TaskException containing these exceptions is thrown when
Wait is called.
Completion Callbacks:
It is possible to specify a completion callbacks when starting a new tasks. For example, see
method Start(Action, Action). The completion callbacks are executed after the
corresponding tasks have completed. Completion callbacks are executed regardless of whether
tasks have completed successfully or have thrown an exception.
However, the callbacks are not executed immediately! Instead, the method RunCallbacks needs to be called manually - usually on the main thread - to invoke the callbacks.
Task Scheduling:
The number of threads used for parallelization is determined by the task scheduler (see
Scheduler). The task scheduler creates a number of threads and distributes the
tasks among these worker threads. The default task scheduler is a
WorkStealingScheduler that creates one thread per CPU core on Windows and 3
threads on Xbox 360 (on the hardware threads 3, 4, and 5). The number of worker threads can be
specified in the constructor of the WorkStealingScheduler.
The property Scheduler can be changed at runtime. The default task scheduler can be replaced with another task scheduler (e.g. with a WorkStealingScheduler that uses a different number of tasks, or with a custom ITaskScheduler). Replacing a task scheduler will affect all future tasks that have not yet been scheduled. However, it is highly recommended to use the default scheduler or specify the scheduler only once at the startup of the application.
Processor Affinity:
In the .NET Compact Framework for Xbox 360 the processor affinity determines the processors on
which a thread runs. Setting the processor affinity in Windows has no effect.
The processor affinity is defined as an array using the property ProcessorAffinity. Each entry in the array specifies the hardware thread that the corresponding worker thread will use. The default value is { 3, 4, 5, 1 }. The default task scheduler reads this array and assigns the worker threads to the specified hardware threads. (See also Thread.SetProcessorAffinity in the MSDN Library to find out more.)
Important: The processor affinity needs to be set before any parallel tasks are created or before a new WorkStealingScheduler is created. Changing the processor affinity afterwards has no effect.
// Configure the class Parallel to use the hardware threads 3 and 4 on the Xbox 360. // (Note: Setting the processor affinity has no effect on Windows.) Parallel.ProcessorAffinity = new[] { 3, 4 }; // Create task scheduler that uses 2 worker threads. Parallel.Scheduler = new WorkStealingScheduler(2); // Note: Above code is usually run at the start of an application. It is not recommended to // change the processor affinity or the task scheduler at runtime of the application.
The following example demonstrates how a task is started.
// Start a method call on another thread: // DoSomeWork can either be an Action delegate, or an object which implements IWork. Task task = Parallel.Start(DoSomeWork); // Do something else on this thread for a while. DoSomethingElse(); // Wait for the task to complete. This ensures that after this call returns, the task has //finished. task.Wait();
The following example demonstrates how task can be used to compute values in parallel and return the result when needed.
// Task<T> is similar to Task, but you can retrieve a result from it. Task<double> piTask = Parallel.Start(CalculatePi); // Do something else for a while. DoSomethingElse(); // Retrieve the result. The caller will block until the task has completed. // GetResult() can only be called once! double pi = piTask.GetResult();
The following example demonstrates how to run a long task in the background to avoid that the current thread is blocked.
// Begin loading some files.
Parallel.StartBackground(LoadFiles);
The following demonstrates how a for-loop can be executed in parallel.
// Sequential loop: for (int i = 0; i < count; i++) { DoWork(i); } // Same loop, but each iteration may happen in parallel on multiple threads. Parallel.For(0, count, i => { DoWork(i); });
The following demonstrates how a foreach-loop can be executed in parallel.
// Sequential loop: foreach (var item in list) { DoWork(item); } // Same loop, but each iteration may happen in parallel on multiple threads. Parallel.ForEach(list, item => { DoWork(item); });