{"id":2253,"date":"2009-03-27T15:49:00","date_gmt":"2009-03-27T15:49:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/pfxteam\/2009\/03\/27\/whats-new-in-beta-1-for-the-task-parallel-library-part-13\/"},"modified":"2009-03-27T15:49:00","modified_gmt":"2009-03-27T15:49:00","slug":"whats-new-in-beta-1-for-the-task-parallel-library-part-13","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/whats-new-in-beta-1-for-the-task-parallel-library-part-13\/","title":{"rendered":"What\u2019s new in Beta 1 for the Task Parallel Library? (Part 1\/3)"},"content":{"rendered":"<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">Related Posts:<\/font><\/p>\n<ul>\n<li>\n<div class=\"MsoNormal\"><a title=\"What&rsquo;s new in Beta 1 for the Task Parallel Library? (Part 2\/3)\" href=\"https:\/\/blogs.msdn.com\/pfxteam\/archive\/2009\/04\/06\/9534426.aspx\" target=\"_blank\">What&rsquo;s new in Beta 1 for the Task Parallel Library? (Part 2\/3)<\/a><\/div>\n<\/li>\n<li>\n<div class=\"MsoNormal\"><a title=\"What's new in the Task Parallel Library for Beta 1 (Part 3\/3)?\" href=\"https:\/\/blogs.msdn.com\/pfxteam\/archive\/2009\/04\/14\/9549246.aspx\" target=\"_blank\"><font color=\"#006ff7\">What&#8217;s new in Beta 1 for the Task Parallel Library? (Part 3\/3)<\/font><\/a><\/div>\n<\/li>\n<\/ul>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">The Task Parallel Library (TPL) has come a long way since its inception.<span>&nbsp; <\/span>Over the course of several CTPs, it has evolved to be an important and central new component in the .NET Framework.<span>&nbsp; <\/span>Most recently, TPL was released as part of mscorlib.dll in the Visual Studio 2010 and .NET Framework 4.0 CTP around the October 2008 timeframe.<span>&nbsp;&nbsp; <\/span>However, due to the nature of large software projects, that release was actually based on code from back in July!<span>&nbsp; <\/span>Needless to say, since last summer, we&rsquo;ve invested a lot of effort into making sure that the right functionality is exposed through the right set of APIs.<span>&nbsp; <\/span>And as a result, TPL has changed considerably.<span>&nbsp; <\/span>In this set of posts, we&rsquo;ll walk through some of the changes so you&rsquo;ll be ready for the next preview release of .NET 4.0 (no guarantees at this time regarding when that will be).<span>&nbsp; <\/span>Of course, as with any software project, TPL may change even more between now and when it&rsquo;s released, so we&rsquo;re very interested in any feedback that you may have!<\/font><\/p>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">In this first post, we&rsquo;ll talk about some changes <b>under the covers<\/b>, some redesigns in <b>System.Threading.Parallel<\/b>, and some new cancellation features (<b>Tasks and Tokens<\/b>).<\/font><\/p>\n<h2><font color=\"#4f81bd\" size=\"4\" face=\"Cambria\">Under the Covers<\/font><\/h2>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">TPL now uses the .NET ThreadPool as its default scheduler.<span>&nbsp; <\/span>As part of this effort, the ThreadPool has undergone a number of significant functional improvements:<\/font><\/p>\n<p class=\"MsoListParagraphCxSpFirst\"><span><span><font size=\"3\">&middot;<\/font><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font face=\"Calibri\"><font size=\"3\"><b>Work-stealing<\/b> queues were introduced internally to be used by TPL (see <a title=\"The New and Improved CLR 4 Thread Pool Engine\" href=\"https:\/\/www.danielmoth.com\/Blog\/2008\/11\/new-and-improved-clr-4-thread-pool.html\" target=\"_blank\">Daniel Moth&#8217;s post<\/a> on the new CLR 4 ThreadPool engine)<\/font><\/font><\/p>\n<p class=\"MsoListParagraphCxSpMiddle\"><span><span><font size=\"3\">&middot;<\/font><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font face=\"Calibri\"><font size=\"3\"><b>Hill-climbing<\/b> algorithms were introduced to quickly determine and adjust to the optimal number of threads for the current workload.<\/font><\/font><\/p>\n<p class=\"MsoListParagraphCxSpLast\"><span><span><font size=\"3\">&middot;<\/font><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font size=\"3\"><font face=\"Calibri\"><b>Coordination and synchronization types <\/b>such as SpinWait and SpinLock are now used internally.<\/font><\/font><\/p>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">Also, the whole of Parallel Extensions just emerged from a performance push.<span>&nbsp; <\/span>In TPL, this included work to decrease the overheads of loops and the launching of Tasks.<span>&nbsp; <\/span>We&rsquo;re by no means done where performance is concerned, but you should notice improved performance for a variety of scenarios.<\/font><\/p>\n<h2><font color=\"#4f81bd\" size=\"4\" face=\"Cambria\">System.Threading.Parallel<\/font><\/h2>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">The TPL feature crew spent many hours in design meetings, and this has resulted in quite a few changes for our Parallel APIs.<span>&nbsp; <\/span>Here are the most significant ones.<\/font><\/p>\n<p class=\"MsoNormal\"><b><font size=\"3\"><font face=\"Calibri\">ParallelOptions<\/p>\n<p><\/font><\/font><\/b><\/p>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">A common request\/question we&rsquo;ve gotten based on previous CTPs is the ability to limit the concurrency level of parallel loops.<span>&nbsp; <\/span>Folks would create a new TaskManager (specifying the number of processors and\/or the number of threads per processor) just to achieve this scenario, and many were still unsuccessful.<span>&nbsp; <\/span>We now provide a better, more intuitive solution.<\/font><\/p>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">The new ParallelOptions class contains properties relevant to the APIs in System.Threading.Parallel.<span>&nbsp; <\/span>One of these properties is MaxDegreeOfParallelism, which does what it sounds like it does.<span>&nbsp; <\/span>The default value, -1, causes a Parallel API to attempt to use all available cores, but this can be overridden.<span>&nbsp; <\/span>For example, the following loop will run on no more than two cores regardless of how many exist in the machine:<\/font><\/p>\n<p class=\"MsoNoSpacing\"><span>var options = new ParallelOptions { MaxDegreeOfParallelism = 2 };<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span>Parallel.For(0, 1000, options, i=&gt;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span>{<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><span>&nbsp;&nbsp;&nbsp; <\/span>&#8230;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span>});<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><font size=\"3\"><font face=\"Calibri\">By consolidating options into the ParallelOptions class, we were able to eliminate quite a few existing overloads and prevent exploding the number of overloads when adding new options.<span>&nbsp; <\/span>Some new properties include a CancellationToken that will be monitored to determine whether a Parallel call should exit early, and a TaskScheduler that can be used to specify the scheduler on which to execute.<span>&nbsp; <\/span>Both of these options are explored more in later sections.<span><\/p>\n<p><\/span><\/font><\/font><\/p>\n<p class=\"MsoNormal\"><b><font size=\"3\"><font face=\"Calibri\">Thread-local State<\/p>\n<p><\/font><\/font><\/b><\/p>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">In previous releases, we supported thread-local state via a ParallelState&lt;TLocal&gt; class.<span>&nbsp; <\/span>For example, to get the sum of 0-99:<\/font><\/p>\n<p class=\"MsoNormal\"><span>int sum = 0;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>Parallel.For(0, 100,<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span>\/\/ Initialize all thread-local states to 0.<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span>() =&gt; { return 0; },<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span>\/\/ Accumulate the iteration count.<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span>(int i, ParallelState&lt;int&gt; loopState) =&gt;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span>{<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>loopState.ThreadLocalState += i;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span>},<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span>\/\/ Accumulate all the final thread-local states.<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span>(int finalThreadLocalState) =&gt;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span>{<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>Interlocked.Add(ref sum, finalThreadLocalState);<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span>});<\/span><span><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">In the above, loopState (a ParallelState&lt;int&gt; instance) stores each of the thread-local states in a property.<span>&nbsp; <\/span>However, loopState would also be used to prematurely break out of the loop (using the Break or Stop methods).<span>&nbsp; <\/span>For a cleaner design, we decided to separate these two functionalities by:<\/font><\/p>\n<p class=\"MsoListParagraphCxSpFirst\"><span><span><font size=\"3\">&middot;<\/font><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font size=\"3\" face=\"Calibri\">Renaming ParallelState to ParallelLoopState (used to break out of loops prematurely, check if a loop has been stopped by another iteration, etc.)<\/font><\/p>\n<p class=\"MsoListParagraphCxSpLast\"><span><span><font size=\"3\">&middot;<\/font><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font size=\"3\" face=\"Calibri\">Removing ParallelState&lt;TLocal&gt; and baking thread-local state into the signatures of Parallel.For and ForEach overloads<\/font><\/p>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">To achieve the above scenario now, the body delegate would be:<\/font><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span>\/\/ Accumulate the iteration count.<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span>(int i, ParallelLoopState loopState, int threadLocalState) =&gt;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span>{<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>return threadLocalState + i;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span>},<\/span><span><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">Note that the body delegate is now a Func that returns a TLocal &ndash; in this case, an int.<span>&nbsp; <\/span>Each iteration of the body is passed the current thread-local state and must return the possibly-updated state.<\/font><\/p>\n<h2><font color=\"#4f81bd\" size=\"4\" face=\"Cambria\">Tasks and Tokens<\/font><\/h2>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">In the previous section, we saw that a CancellationToken may be used to cancel a Parallel call.<span>&nbsp; <\/span>This token structure is actually part of a new unified cancellation model that is intended for eventual use throughout the .NET Framework.<span>&nbsp; <\/span>As of Beta 1, it is supported by a few TPL APIs such as Wait:<\/font><\/p>\n<p class=\"MsoNormal\"><span>Task t = &#8230;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>CancellationTokenSource tokenSource = new CancellationTokenSource();<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>CancellationToken token = tokenSource.Token;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>try { t.Wait(token); }<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>catch (OperationCanceledException oce) { }<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span>\/\/ Elsewhere&#8230;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span>tokenSource.Cancel();<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><font size=\"3\"><font face=\"Calibri\">The new cancellation model centers around two types: CancellationTokenSource and CancellationToken.<span>&nbsp; <\/span>A CancellationTokenSource is used to cancel its member CancellationToken (accessible via the Token property).<span>&nbsp; <\/span>A CancellationToken can only be used to check whether cancellation has been requested; separating the ability to cancel and the ability to check for cancellation requests is a key point in the new model.<span>&nbsp; <\/span>In the above example, the Wait operation is passed a CancellationToken, and the associated CancellationTokenSource is used to cancel the operation; note that it is the Wait operation that gets canceled, not the Task.<\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font size=\"3\"><font face=\"Calibri\">As mentioned in the &ldquo;What&rsquo;s new in CDS&rdquo; post, cancellation merits a dedicated post, so look for that one soon.<\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font size=\"3\"><font face=\"Calibri\">Check back soon for &ldquo;What&rsquo;s new in Beta 1 for TPL (Part 2\/3)&rdquo;!<\/p>\n<p><\/font><\/font><\/span><\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Related Posts: What&rsquo;s new in Beta 1 for the Task Parallel Library? (Part 2\/3) What&#8217;s new in Beta 1 for the Task Parallel Library? (Part 3\/3) The Task Parallel Library (TPL) has come a long way since its inception.&nbsp; Over the course of several CTPs, it has evolved to be an important and central new [&hellip;]<\/p>\n","protected":false},"author":485,"featured_media":58792,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[7908],"tags":[],"class_list":["post-2253","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-pfxteam"],"acf":[],"blog_post_summary":"<p>Related Posts: What&rsquo;s new in Beta 1 for the Task Parallel Library? (Part 2\/3) What&#8217;s new in Beta 1 for the Task Parallel Library? (Part 3\/3) The Task Parallel Library (TPL) has come a long way since its inception.&nbsp; Over the course of several CTPs, it has evolved to be an important and central new [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/2253","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/485"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=2253"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/2253\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58792"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=2253"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=2253"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=2253"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}