What’s New in the June 2008 CTP of Parallel Extensions

Stephen Toub - MSFT

We’ve just released a new community technology preview (CTP) of Parallel Extensions to the .NET Framework!  You can download it from https://www.microsoft.com/downloads/details.aspx?FamilyId=348F73FD-593D-4B3C-B055-694C50D2B0F3.  This release contains a plethora of bug fixes as well as some design changes to address some great feedback from you (note that there are some other changes you’ve requested and that we’re planning to make in future releases, so stay tuned).  It also contains a wealth of new functionality, some under the covers, some exposed through new APIs.

Task Parallel Library

The December 2007 CTP included an implementation of the Task Parallel Library (TPL) built on top of a prototype scheduler. As we’ve moved forward with Parallel Extensions, we’ve replaced this prototype with a new scheduler that is built from the ground up to be more robust, efficient, and scalable. The scheduler uses cooperative scheduling and work-stealing to achieve fast, efficient scheduling and maximum CPU utilization. The June 2008 CTP of Parallel Extensions includes this new scheduler, with TPL running on top of it.
While lots of work has been done with the internals of TPL, new functionality has also been exposed through its APIs. A new continuation model has been added to the System.Threading.Tasks.Task and System.Threading.Tasks.Future<T> classes through a new set of ContinueWith methods on both Task and Future<T>, enabling new tasks to be scheduled when previous tasks complete. This is especially powerful for Future<T>, where the continuations are provided with the completed Future<T> and thus with access to its Value, enabling dataflow-oriented solutions, e.g.:

var futureC = Future.Create(() => A()).
ContinueWith(a => B(a.Value)).
ContinueWith(b => C(b.Value));

Continuations can be scheduled to run under a variety of circumstances, such as when a task completes due to an unhandled exception.

Other new functionality includes a new set of WaitAny methods on Task that serve as counterparts to Task’s WaitAll methods (TaskCoordinator, which existed in the December 2007 CTP as the base class for Task and which exposed the WaitAll methods, has been removed). WaitAny enables a developer to wait for any one of a set of tasks to complete, which can be useful for a variety of scenarios, including speculative execution. Consider a problem where multiple heuristics can be used to solve the problem, but it’s not known a priori which algorithm will solve the problem the fastest. If it’s not feasible to parallelize each of the algorithms, the algorithms could all be run in parallel with one another, and the developer can use WaitAny to wait for the first algorithm to complete, e.g.:

var algorithms = new[] {
    Future.Create(() => Alg1()) ,
    Future.Create(() => Alg2()) ,
    Future.Create(() => Alg3()) ,
    Future.Create(() => Alg4()) };
var result = algorithms[Task.WaitAny(algorithms)].Value;

Several new properties have emerged on the Task class. The Name property that appeared in the December 2007 CTP has been replaced by an Id property, and a Creator property has been added. Creator returns the Task that was current when the Task was created. Creator is similar but is not always identical to the Parent property. New in this CTP is an improved notion of task hierarchies and relationships between parent and child tasks. By default, a Task is parented to the Task that was current when it was created; in this case, both Parent and Creator will return the same Task instance. However, Tasks can be created detached from their creator (by specifying the TaskCreationOptions.Detached value), in which case Parent will return null. This is an important capability, because now by default parent tasks implicitly wait on their children before completing, enabling a more structured form of task parallelism and aiding in a developer’s ability to write a correct, task-based application.

A variety of additional and minor API changes have also surfaced in this CTP. The TaskManagerPolicy class contains new values, representing concepts such as the minimum number of processors to use, the ideal number of processors to use, the ideal number of threads to use per processor, the stack size to use per thread, and the thread priority to assign to threads. At a higher-level, the Parallel.Do method has been renamed to Parallel.Invoke. Significant effort has also been invested in fixing bugs in functionality.

PLINQ

The most important changes in this CTP are implementation details for improving the reliability and debuggability of PLINQ. One such change: whereas PLINQ in the December 2007 CTP release was built on top of the .NET ThreadPool, PLINQ in this CTP is now built on top of the Task Parallel Library. Note, however, that this implementation is minimalistic. The plan is for future releases to take advantage of more of the functionality the Task Parallel Library has to offer.

In addition to implementation changes, new APIs are present in this CTP. First and foremost, the APIs for specifying order-preservation have been revamped. In the previous CTP, order-preservation was enabled on a query using the ParallelQueryOptions enumeration, such as in this example written in Visual Basic:

Public Shared Function Scramble(ByVal words As String()) As String()
    Return (From word In words.AsParallel(ParallelQueryOptions.PreserveOrdering) _
               Select ScrambleWord(word)).ToArray()
End Function

The ParallelQueryOptions enumeration has been removed from the API set, and has been replaced by a new AsOrdered extension method, which can be used as follows:

Public Shared Function Scramble(ByVal words As String()) As String()
    Return (From word In words.AsParallel().AsOrdered() _
               Select ScrambleWord(word)).ToArray()
End Function

An AsUnordered extension method also exists to enable the introduction of “shuffle points” into a query. If a certain portion of a query must be processed with a specific ordering, AsOrdered or OrderBy can be used to ensure that ordering is preserved, while AsUnordered can be used to in effect turn off ordering for portions of the query where performance is more important than ordering.

Other API level changes include the introduction of a new extension method, Zip:

public static IParallelEnumerable<TResult> 
Zip<TFirst, TSecond, TResult>( this IParallelEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> resultSelector);

Zip “zips together” two enumerables, creating a pairing of an item from each enumeration that is then passed to a function. An enumerable containing the results of that function is returned. This CTP also includes a parallel implementation of the SequenceEquals extension method, which was omitted from the previous CTP. Additionally, the Cast and OfType operators have been updated to conform to a breaking change in LINQ-to-Object’s implementation of these operators that’s available in the .NET Framework 3.5 SP1 (more information about this change is available at https://blogs.msdn.com/ed_maurer/archive/2008/02/16/breaking-change-in-linq-queries-using-explicitly-typed-range-variables.aspx).

Coordination Data Structures

The June 2008 CTP introduces a set of coordination data structures that complement PLINQ and the Task Parallel Library. The System.Threading namespace of the .NET Framework 3.5 already contains a handful of synchronization primitives, such as events, monitors, and mutexes, which are low-level constructs useful in developing multithreaded applications. Many parallel applications, however, would benefit greatly from higher-level constructs such as thread-safe collections, more sophisticated locking primitives, data structures to facilitate work exchange, and types that control how variables are initialized. Parallel Extensions adds a plethora of such constructs to the System.Threading and System.Threading.Collections namespaces. The types included in this CTP are:

  • System.Threading.CountdownEvent
  • System.Threading.LazyInit<T>
  • System.Threading.ManualResetEventSlim
  • System.Threading.SemaphoreSlim
  • System.Threading.SpinLock
  • System.Threading.SpinWait
  • System.Threading.WriteOnce<T>
  • System.Threading.Collections.BlockingCollection<T>
  • System.Threading.Collections.ConcurrentQueue<T>
  • System.Threading.Collections.ConcurrentStack<T>

0 comments

Discussion is closed.

Feedback usabilla icon