<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Parallel Programming with .NET : .NET 4.0</title><link>http://blogs.msdn.com/pfxteam/archive/tags/.NET+4.0/default.aspx</link><description>Tags: .NET 4.0</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Updated Beta 2 samples for parallel programming</title><link>http://blogs.msdn.com/pfxteam/archive/2009/12/06/9933262.aspx</link><pubDate>Mon, 07 Dec 2009 03:59:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9933262</guid><dc:creator>toub</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/9933262.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=9933262</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=9933262</wfw:comment><description>&lt;P&gt;We've refreshed our Beta 2 samples for parallel programming with the .NET Framework 4.&amp;nbsp; Thanks to the gracious assistance of the fabulous &lt;A href="http://msdn.microsoft.com/en-us/vbasic/bb735849.aspx#feigenbaum" mce_href="http://msdn.microsoft.com/en-us/vbasic/bb735849.aspx#feigenbaum"&gt;Lisa Feigenbaum&lt;/A&gt; and others on the Visual Basic team, in this refresh the majority of the samples are now available not only in C# but also in Visual Basic. The samples are available for download at &lt;A href="http://code.msdn.microsoft.com/ParExtSamples" mce_href="http://code.msdn.microsoft.com/ParExtSamples"&gt;http://code.msdn.microsoft.com/ParExtSamples&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;Enjoy!&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9933262" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Code+Samples/default.aspx">Code Samples</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Release/default.aspx">Release</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/.NET+4.0/default.aspx">.NET 4.0</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/.NET+4/default.aspx">.NET 4</category></item><item><title>What’s new in Beta 2 for the Task Parallel Library? (Part 2/3)</title><link>http://blogs.msdn.com/pfxteam/archive/2009/10/27/9913610.aspx</link><pubDate>Tue, 27 Oct 2009 18:02:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9913610</guid><dc:creator>dashih</dc:creator><slash:comments>10</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/9913610.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=9913610</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=9913610</wfw:comment><description>&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT face=Calibri&gt;&lt;FONT size=3&gt;Related posts:&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT face=Calibri&gt;&lt;FONT size=3&gt;&lt;SPAN style="mso-ansi-language: EN" lang=EN&gt;&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&lt;A href="http://blogs.msdn.com/pfxteam/archive/2009/10/19/9909371.aspx" mce_href="http://blogs.msdn.com/pfxteam/archive/2009/10/19/9909371.aspx"&gt;&lt;FONT size=3 face=Calibri&gt;What's new in Beta 2 for the Task Parallel Library (1/3)&lt;/FONT&gt;&lt;/A&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;A title="What's new in Beta 2 for the Task Parallel Library (3/3)" href="http://blogs.msdn.com/pfxteam/archive/2009/11/04/9917581.aspx" target=_blank mce_href="http://blogs.msdn.com/pfxteam/archive/2009/11/04/9917581.aspx"&gt;&lt;FONT size=3 face=Calibri&gt;What's new in Beta 2 for the Task Parallel Library (3/3)&lt;/FONT&gt;&lt;/A&gt;&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Last week, we talked about how TPL adopted a new, better cancellation model.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Today, we’ll cover a change that makes &lt;B style="mso-bidi-font-weight: normal"&gt;Tasks Detached by Default&lt;/B&gt;, some &lt;B style="mso-bidi-font-weight: normal"&gt;ContinueWhenAll/Any Refactoring&lt;/B&gt;, and the handy &lt;B style="mso-bidi-font-weight: normal"&gt;UnobservedTaskException event&lt;/B&gt;.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;H2 style="MARGIN: 10pt 0in 0pt"&gt;&lt;FONT size=4&gt;&lt;FONT color=#4f81bd&gt;&lt;FONT face=Cambria&gt;Tasks are Detached by Default&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/H2&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;In Beta 2, we have changed an important default.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Tasks are now created as detached (instead of attached) if no options specify otherwise.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Let’s consider the following code to review the difference between attached and detached Tasks.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;Task p = Task.Factory.StartNew(() =&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;Task c = Task.Factory.StartNew(() =&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;DoWork();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;});&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;});&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;p.Wait();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;In Beta 1 and before, since the default options are used, ‘c’ is created as a child Task of Task ‘p’, the parent Task; we refer to this as Task ‘c’ being “attached” to Task ‘p’.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This means that the p.Wait() statement will not return until the call to DoWork completes, because parent Tasks do not complete until all of their child Tasks complete.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;To opt out of this behavior, a user needs to create ‘c’ with the DetachedFromParent option:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;Task c = Task.Factory.StartNew(() =&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;DoWork();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;}, &lt;B style="mso-bidi-font-weight: normal"&gt;TaskCreationOptions.DetachedFromParent&lt;/B&gt;);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;&lt;U&gt;The original code shown behaves differently in Beta 2&lt;/U&gt;.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Now, by default, ‘c’ is not related to ‘p’ (it’s “detached” by default), and the p.Wait() statement will return as soon as ‘p’ completes, regardless of the status of Task ‘c’ and thus regardless of when DoWork returns.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;To opt in to the parent/child relationship, a user needs to create ‘c’ with the AttachedToParent option:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;Task c = Task.Factory.StartNew(() =&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;DoWork();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;}, &lt;B style="mso-bidi-font-weight: normal"&gt;TaskCreationOptions.AttachedToParent&lt;/B&gt;);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT face=Calibri&gt;&lt;FONT size=3&gt;Here is a summary of the changes:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 0pt 0.5in; mso-list: l1 level1 lfo1" class=MsoListParagraphCxSpFirst&gt;&lt;SPAN style="FONT-FAMILY: Symbol; mso-fareast-font-family: Symbol; mso-bidi-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3&gt;·&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri&gt;&lt;FONT size=3&gt;Removed the DetachedFromParent option&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 0pt 0.5in; mso-list: l1 level1 lfo1" class=MsoListParagraphCxSpMiddle&gt;&lt;SPAN style="FONT-FAMILY: Symbol; mso-fareast-font-family: Symbol; mso-bidi-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3&gt;·&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri&gt;&lt;FONT size=3&gt;Added the AttachedToParent option&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 10pt 0.5in; mso-list: l1 level1 lfo1" class=MsoListParagraphCxSpLast&gt;&lt;SPAN style="FONT-FAMILY: Symbol; mso-fareast-font-family: Symbol; mso-bidi-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3&gt;·&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri&gt;&lt;FONT size=3&gt;Changed the default behavior so that Tasks do not enlist in parent/child relationships when no options are specified.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT face=Calibri&gt;&lt;FONT size=3&gt;There were a number of reasons why we decided that detached is the correct default and to move forward with this change, including:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 0pt 0.5in; mso-list: l2 level1 lfo2" class=MsoListParagraphCxSpFirst&gt;&lt;SPAN style="FONT-FAMILY: Symbol; mso-fareast-font-family: Symbol; mso-bidi-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3&gt;·&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri&gt;&lt;FONT size=3&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;Many users were using attached Tasks unknowingly.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;&lt;/B&gt;The vast majority of the time, users create Tasks for simple, asynchronous work.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In such scenarios, parent/child relationships (and the implicit waiting) are not needed.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;We found through many interactions that folks were just going with the default options and were accidentally opting in to this behavior.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In the best case, this would only result in a slight performance cost. &lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/SPAN&gt;In the worst case, this would bring with it incorrect behavior that would lead to difficult to diagnose errors.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 0pt 0.5in; mso-list: l2 level1 lfo2" class=MsoListParagraphCxSpMiddle&gt;&lt;SPAN style="FONT-FAMILY: Symbol; mso-fareast-font-family: Symbol; mso-bidi-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3&gt;·&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri&gt;&lt;FONT size=3&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;Easier migration from ThreadPool.QueueUserWorkItem&lt;/B&gt;.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Tasks are now the recommended way to queue work to the ThreadPool, but the easiest way to create Tasks resulted in different behavior from QueueUserWorkItem (where there’s no concept of parent/child work items).&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This change makes Task.Factory.StartNew (with no options) a true replacement for QueueUserWorkItem.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 10pt 0.5in; mso-list: l2 level1 lfo2" class=MsoListParagraphCxSpLast&gt;&lt;SPAN style="FONT-FAMILY: Symbol; mso-fareast-font-family: Symbol; mso-bidi-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3&gt;·&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;&lt;B style="mso-bidi-font-weight: normal"&gt;Additional behavior should be opt-in and pay-for-play&lt;/B&gt;.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Almost everything in TPL that results in additional behavior is opt-in, e.g. cancellation, LongRunning, PreferFairness.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;With the Beta 1 default, users opt-out of parent/child relationships.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In Beta 2, users opt-in, making it consistent.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This makes the extra functionality provided by parent/child relationships pay-for-play, such that you don’t pay the cost for parents implicitly waiting for their children or for exceptions propagating from children to parents unless you need that functionality.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;H1 style="MARGIN: 24pt 0in 0pt"&gt;&lt;FONT size=5&gt;&lt;FONT color=#376092&gt;&lt;FONT face=Cambria&gt;ContinueWhenAny/All Refactoring&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/H1&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;We have refactored the set of ContinueWhenAny and ContinueWhenAll overloads to make things more intuitive, consistent, and complete.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;To demonstrate the main issue, let’s consider the following overload that was provided in Beta 1.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 0pt 0.5in" class=MsoNoSpacing&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;public class TaskFactory&amp;lt;TResult&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 0pt 0.5in" class=MsoNoSpacing&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 0pt 0.5in" class=MsoNoSpacing&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;public Task&amp;lt;TNewResult&amp;gt; ContinueWhenAny(&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 0pt 0.5in" class=MsoNoSpacing&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;Task&amp;lt;TResult&amp;gt;[] tasks, &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 0pt 0.5in" class=MsoNoSpacing&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;Func&amp;lt;Task&amp;lt;TResult&amp;gt;, TNewResult&amp;gt; continuationFunction);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 0pt 0.5in" class=MsoNoSpacing&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 0pt 0.5in" class=MsoNoSpacing&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;This confused the meaning of TaskFactory&amp;lt;TResult&amp;gt;, which is meant to create tasks of type Task&amp;lt;TResult&amp;gt;.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;However, with these overloads, TaskFactory&amp;lt;TResult&amp;gt; could be used to create tasks of type Task&amp;lt;TNewResult&amp;gt;. As an example, consider the code:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt 0.5in" class=MsoNormal&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;Task&amp;lt;int&amp;gt;[] taskOfInts = ...;&lt;BR&gt;Task&amp;lt;&lt;B style="mso-bidi-font-weight: normal"&gt;string&lt;/B&gt;&amp;gt; t = Task&amp;lt;&lt;B style="mso-bidi-font-weight: normal"&gt;int&lt;/B&gt;&amp;gt;.Factory.ContinueWhenAll(taskOfInts, _ =&amp;gt; “”);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;This compiles and works just fine, but the type parameter mismatch (shown in bold) is certainly odd.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;To address this, we changed a bunch of overloads, so that instead of taking Task&amp;lt;TResult&amp;gt;s and returning a Task&amp;lt;TNewResult&amp;gt;, they take Task&amp;lt;TAntecedentResult&amp;gt;s and return Task&amp;lt;TResult&amp;gt;s.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;For example, the overload that replaced the above is:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 0pt 0.5in" class=Code&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;public Task&amp;lt;TResult&amp;gt; ContinueWhenAny&amp;lt;TAntecedentResult&amp;gt;(&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 0pt 0.5in" class=Code&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Task&amp;lt;TAntecedentResult&amp;gt;[] tasks,&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 0pt 0.5in" class=Code&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Func&amp;lt;Task&amp;lt;TAntecedentResult&amp;gt;, TResult&amp;gt; continuationFunction);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 0pt 0.5in" class=Code&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;And the above example becomes:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt 0.5in" class=MsoNormal&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;Task&amp;lt;int&amp;gt;[] taskOfInts = ...;&lt;BR&gt;Task&amp;lt;string&amp;gt; t = Task&amp;lt;string&amp;gt;.Factory.ContinueWhenAll(taskOfInts, _ =&amp;gt; “”);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT face=Calibri&gt;&lt;FONT size=3&gt;In addition to this change, we also added, removed, or modified a number of other overloads to make the set consistent and complete.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Now, the entire set of ContinueWhenAll and ContinueWhenAny overloads follow these clear rules:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 0pt 0.5in; mso-list: l0 level1 lfo3" class=MsoListParagraphCxSpFirst&gt;&lt;SPAN style="FONT-FAMILY: Symbol; mso-fareast-font-family: Symbol; mso-bidi-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3&gt;·&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri&gt;&lt;FONT size=3&gt;A TaskFactory creates Tasks, but also provides overloads to create Task&amp;lt;TResult&amp;gt;s.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 10pt 0.5in; mso-list: l0 level1 lfo3" class=MsoListParagraphCxSpLast&gt;&lt;SPAN style="FONT-FAMILY: Symbol; mso-fareast-font-family: Symbol; mso-bidi-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3&gt;·&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;A TaskFactory&amp;lt;TResult&amp;gt; only ever creates Task&amp;lt;TResult&amp;gt;s (never Tasks or Task&amp;lt;TNewResult&amp;gt;s).&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;H1 style="MARGIN: 24pt 0in 0pt"&gt;&lt;FONT size=5&gt;&lt;FONT color=#376092&gt;&lt;FONT face=Cambria&gt;UnobservedTaskException event&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/H1&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;We’ve added an event that fires for every Task exception that goes unobserved.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Recall that to “observe” a Task’s exceptions, you must either Wait on the Task or access its Exception property after it has completed.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;At least one of these actions must be done before the Task object is garbage collected, or its exceptions will propagate (currently this occurs on the finalizer thread).&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;The new static event resides on the TaskScheduler class, and subscribing to it is straightforward.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Here’s an example to log all unobserved exceptions and mark them as observed (preventing them from being propagated).&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 0pt 0.5in" class=MsoNoSpacing&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;TaskScheduler.UnobservedTaskException += &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 0pt 0.5in" class=MsoNoSpacing&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;(object sender, UnobservedTaskExceptionEventArgs exceptionArgs) =&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 0pt 0.5in" class=MsoNoSpacing&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 0pt 0.5in" class=MsoNoSpacing&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;exceptionArgs.SetObserved();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 0pt 0.5in" class=MsoNoSpacing&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;LogException(exceptionArgs.Exception);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 0pt 0.5in" class=MsoNoSpacing&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;};&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 0pt 0.5in" class=MsoNoSpacing&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Some customers have complained that TPL’s exception policy is too strict.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The UnobservedTaskException event provides an easy way out by allowing you to simply squash all Task exceptions in an application (though using it in this manner is not recommended).&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The primary reason that we made the addition was to support host-plugin scenarios where a host application can still be perfectly useful in the presence of some truly harmless exceptions (thrown by buggy plugins).&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;These scenarios may be achieved using the UnobservedTaskException event in conjunction with AppDomains to sandbox plugins.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Look for a future post that describes this in more detail!&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;We’re done for now!&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The 3&lt;SUP&gt;rd&lt;/SUP&gt; and final post of this series will cover the new Unwrap APIs, a Parallel namespace change, and some changes under the covers.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9913610" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Visual+Studio+2010/default.aspx">Visual Studio 2010</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/.NET+4.0/default.aspx">.NET 4.0</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Beta/default.aspx">Beta</category></item><item><title>What’s new in Beta 2 for the Task Parallel Library? (Part 1/3)</title><link>http://blogs.msdn.com/pfxteam/archive/2009/10/19/9909371.aspx</link><pubDate>Mon, 19 Oct 2009 19:42:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9909371</guid><dc:creator>dashih</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/9909371.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=9909371</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=9909371</wfw:comment><description>&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Related&amp;nbsp;posts:&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;&lt;A title="What's new in Beta 2 for the Task Parallel Library? (Part 2/3)" href="http://blogs.msdn.com/pfxteam/archive/2009/10/27/9913610.aspx" mce_href="http://blogs.msdn.com/pfxteam/archive/2009/10/27/9913610.aspx"&gt;What's new in Beta 2 for the Task Parallel Library? (Part 2/3)&lt;/A&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;
&lt;DIV style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;&lt;A title="What's new in Beta 2 for the Task Parallel Library? (Part 3/3)" href="http://blogs.msdn.com/pfxteam/archive/2009/11/04/9917581.aspx" target=_blank mce_href="http://blogs.msdn.com/pfxteam/archive/2009/11/04/9917581.aspx"&gt;What's new in Beta 2 for the Task Parallel Library? (Part 3/3)&lt;/A&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Visual Studio 2010 and .NET 4 Beta 2 is&amp;nbsp;here!&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In terms of completeness and readiness for production coding, Beta 2 promises to be much better than Beta 1, and TPL is one component that delivers significant improvements over what was previously available.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;To get you excited about it, this series of posts details key additions and changes for Beta 2.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Enjoy!&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;In this post, we’re talking about &lt;B style="mso-bidi-font-weight: normal"&gt;cancellation&lt;/B&gt;.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;A few months ago, our flurry of “What’s new in Beta 1” posts hinted at a new cancellation model and promised more information about it.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;We made good on that promise with &lt;/FONT&gt;&lt;A href="http://blogs.msdn.com/pfxteam/archive/2009/05/22/9635790.aspx" mce_href="http://blogs.msdn.com/pfxteam/archive/2009/05/22/9635790.aspx"&gt;&lt;FONT color=#0000ff size=3 face=Calibri&gt;.NET 4 Cancellation Framework&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;, and this post goes further to explain how TPL, specifically, has fully adopted the new model.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;H2 style="MARGIN: 10pt 0in 0pt"&gt;&lt;FONT size=4&gt;&lt;FONT color=#4f81bd&gt;&lt;FONT face=Cambria&gt;The Old Way (Beta 1 and before)&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/H2&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Let’s consider the following code to review the old TPL cancellation model.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;Task myTask = Task.Factory.StartNew(() =&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;for (; ; )&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;if (Task.Current.IsCancellationRequested)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;Task.Current.AcknowledgeCancellation();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;return;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;...&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;});&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;// Elsewhere.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;myTask.Cancel();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;myTask just loops infinitely, checking its IsCancellationRequested property to see if it has been canceled.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Elsewhere, cancellation is requested on myTask using the Cancel method.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;At that point, myTask agrees to get canceled by calling its AcknowledgeCancellation method and returning.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This is all necessary, because Task cancellation is cooperative; &lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/SPAN&gt;to enter the Canceled state, outside logic must request cancellation &lt;U&gt;and&lt;/U&gt; the Task must acknowledge that cancellation request.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;However, note that cooperative cancellation is only relevant for already running Tasks.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;If a Task’s Cancel method is called before it is in the Running state, it will transition directly into the Canceled state.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Waiting on a canceled Task results in a TaskCanceledException wrapped in an AggregateException, hence the try/catch block.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Executing this code prints “Canceled” to the console, indicating that myTask was successfully canceled.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;This approach works, but we identified a number of problems with it including the following:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 0pt 0.5in; mso-list: l0 level1 lfo1" class=MsoListParagraphCxSpFirst&gt;&lt;SPAN style="mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3 face=Calibri&gt;1.&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;The cancellation model required exposing a Task.Current static property.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This leaks implementation details from libraries that utilize Tasks internally; any code called from the Task can muck with the current Task or take dependencies on its existence.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Imagine calling into 3&lt;SUP&gt;rd&lt;/SUP&gt; party code and having that code cancel your Tasks, schedule continuations off of them, etc.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 0pt 0.5in; mso-list: l0 level1 lfo1" class=MsoListParagraphCxSpMiddle&gt;&lt;SPAN style="mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3 face=Calibri&gt;2.&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Anyone with a Task’s reference can request cancellation on it.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In many scenarios, it is valuable to separate the ability to check for cancellation and the ability to actually request cancellation.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 0pt 0.5in; mso-list: l0 level1 lfo1" class=MsoListParagraphCxSpMiddle&gt;&lt;SPAN style="mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3 face=Calibri&gt;3.&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;From a cancellation perspective, Tasks didn’t compose well with other APIs that were cancelable, such as executing a cancelable PLINQ query inside of a Task.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 10pt 0.5in; mso-list: l0 level1 lfo1" class=MsoListParagraphCxSpLast&gt;&lt;SPAN style="mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3 face=Calibri&gt;4.&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Tasks were often more expensive than they needed to be, due to needing to track extra cancellation state per Task.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;H2 style="MARGIN: 10pt 0in 0pt"&gt;&lt;FONT size=4&gt;&lt;FONT color=#4f81bd&gt;&lt;FONT face=Cambria&gt;The New Way (Beta 2 and beyond)&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/H2&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;The new TPL cancellation model is centered around two types: CancellationTokenSource and CancellationToken.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;You can read up about them in the post linked to above, but here is a simplified overview of their APIs:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt 0.5in" class=MsoNormal&gt;&lt;SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; FONT-SIZE: 9pt; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi"&gt;namespace System.Threading&lt;BR&gt;{&lt;BR&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;public sealed class CancellationTokenSource&lt;BR&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{&lt;BR&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;public void Cancel();&lt;BR&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;public CancellationToken Token { get; }&lt;BR&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;...&lt;BR&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;}&lt;BR&gt;&lt;BR&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;public struct CancellationToken&lt;BR&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{&lt;BR&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;public Boolean IsCancellationRequested { get; }&lt;BR&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;public void ThrowIfCancellationRequested();&lt;BR&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;...&lt;BR&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;}&lt;BR&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT face=Calibri&gt;&lt;FONT size=3&gt;Here’s the gist.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;A CancellationTokenSource contains a CancellationToken, and it can request cancellation on that token using a Cancel method.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;A CancellationToken can only check if cancellation has been requested on it.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Ignore the ThrowIfCancellationRequested method for now; we’ll see why it’s handy later.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT face=Calibri&gt;&lt;FONT size=3&gt;Adopting the new model involved not only adding support for these two types, but also ripping out the old model.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Here’s a summary of the changes:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 0pt 0.5in; mso-list: l1 level1 lfo2" class=MsoListParagraphCxSpFirst&gt;&lt;SPAN style="FONT-FAMILY: Symbol; mso-fareast-font-family: Symbol; mso-bidi-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3&gt;·&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri&gt;&lt;FONT size=3&gt;All cancellation-related APIs on the Task class were removed (Cancel, AcknowledgeCancellation, IsCancellationRequested, etc)&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 0pt 0.5in; mso-list: l1 level1 lfo2" class=MsoListParagraphCxSpMiddle&gt;&lt;SPAN style="FONT-FAMILY: Symbol; mso-fareast-font-family: Symbol; mso-bidi-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3&gt;·&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri&gt;&lt;FONT size=3&gt;Other APIs that were no longer relevant were removed (Task.Current, Task.Parent, TaskCreationOptions.RespectParentCancellation, etc)&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 10pt 0.5in; mso-list: l1 level1 lfo2" class=MsoListParagraphCxSpLast&gt;&lt;SPAN style="FONT-FAMILY: Symbol; mso-fareast-font-family: Symbol; mso-bidi-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3&gt;·&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Overloads that accept CancellationToken were added to many methods (StartNew, ContinueWith, etc)&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;And now, here’s a table that outlines how achieving cancellation in TPL has changed:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;TABLE style="BORDER-BOTTOM: medium none; BORDER-LEFT: medium none; BORDER-COLLAPSE: collapse; BORDER-TOP: medium none; BORDER-RIGHT: medium none; mso-border-top-alt: solid black 1.0pt; mso-border-top-themecolor: text1; mso-border-bottom-alt: solid black 1.0pt; mso-border-bottom-themecolor: text1; mso-yfti-tbllook: 1184; mso-padding-alt: 0in 5.4pt 0in 5.4pt" class=LightShading1 border=1 cellSpacing=0 cellPadding=0 class="LightShading1"&gt;
&lt;TBODY&gt;
&lt;TR style="mso-yfti-irow: -1; mso-yfti-firstrow: yes"&gt;
&lt;TD style="BORDER-BOTTOM: black 1pt solid; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0in; BACKGROUND-COLOR: transparent; PADDING-LEFT: 5.4pt; WIDTH: 159.6pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: black 1pt solid; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0in; mso-border-top-themecolor: text1; mso-border-bottom-themecolor: text1" vAlign=top width=213&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-yfti-cnfc: 5" class=MsoNormal&gt;&lt;B&gt;&lt;SPAN style="COLOR: black; FONT-SIZE: 9pt; mso-themecolor: text1; mso-themeshade: 191"&gt;&lt;FONT face=Calibri&gt;Action&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/B&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style="BORDER-BOTTOM: black 1pt solid; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0in; BACKGROUND-COLOR: transparent; PADDING-LEFT: 5.4pt; WIDTH: 159.6pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: black 1pt solid; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0in; mso-border-top-themecolor: text1; mso-border-bottom-themecolor: text1" vAlign=top width=213&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-yfti-cnfc: 1" class=MsoNormal&gt;&lt;B&gt;&lt;SPAN style="COLOR: black; FONT-SIZE: 9pt; mso-themecolor: text1; mso-themeshade: 191"&gt;&lt;FONT face=Calibri&gt;Old Model&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/B&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style="BORDER-BOTTOM: black 1pt solid; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0in; BACKGROUND-COLOR: transparent; PADDING-LEFT: 5.4pt; WIDTH: 159.6pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: black 1pt solid; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0in; mso-border-top-themecolor: text1; mso-border-bottom-themecolor: text1" vAlign=top width=213&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-yfti-cnfc: 1" class=MsoNormal&gt;&lt;B&gt;&lt;SPAN style="COLOR: black; FONT-SIZE: 9pt; mso-themecolor: text1; mso-themeshade: 191"&gt;&lt;FONT face=Calibri&gt;New Model&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/B&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="mso-yfti-irow: 0"&gt;
&lt;TD style="BORDER-BOTTOM: #f0f0f0; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0in; PADDING-LEFT: 5.4pt; WIDTH: 159.6pt; PADDING-RIGHT: 5.4pt; BACKGROUND: #bfbfbf; BORDER-TOP: #f0f0f0; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0in; mso-background-themecolor: text1; mso-background-themetint: 63" vAlign=top width=213&gt;&lt;FONT face=Calibri&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD style="BORDER-BOTTOM: #f0f0f0; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0in; PADDING-LEFT: 5.4pt; WIDTH: 159.6pt; PADDING-RIGHT: 5.4pt; BACKGROUND: #bfbfbf; BORDER-TOP: #f0f0f0; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0in; mso-background-themecolor: text1; mso-background-themetint: 63" vAlign=top width=213&gt;&lt;FONT face=Calibri&gt;&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD style="BORDER-BOTTOM: #f0f0f0; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0in; PADDING-LEFT: 5.4pt; WIDTH: 159.6pt; PADDING-RIGHT: 5.4pt; BACKGROUND: #bfbfbf; BORDER-TOP: #f0f0f0; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0in; mso-background-themecolor: text1; mso-background-themetint: 63" vAlign=top width=213&gt;&lt;FONT face=Calibri&gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="mso-yfti-irow: 1"&gt;
&lt;TD style="BORDER-BOTTOM: #f0f0f0; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0in; BACKGROUND-COLOR: transparent; PADDING-LEFT: 5.4pt; WIDTH: 159.6pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: #f0f0f0; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0in" vAlign=top width=213&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-yfti-cnfc: 4" class=MsoNormal&gt;&lt;SPAN style="COLOR: black; FONT-SIZE: 9pt; mso-bidi-font-weight: bold; mso-themecolor: text1; mso-themeshade: 191"&gt;&lt;FONT face=Calibri&gt;To set up cancellation&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style="BORDER-BOTTOM: #f0f0f0; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0in; BACKGROUND-COLOR: transparent; PADDING-LEFT: 5.4pt; WIDTH: 159.6pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: #f0f0f0; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0in" vAlign=top width=213&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt" class=MsoNormal&gt;&lt;SPAN style="COLOR: black; FONT-SIZE: 9pt; mso-themecolor: text1; mso-themeshade: 191"&gt;&lt;FONT face=Calibri&gt;Just create a Task&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style="BORDER-BOTTOM: #f0f0f0; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0in; BACKGROUND-COLOR: transparent; PADDING-LEFT: 5.4pt; WIDTH: 159.6pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: #f0f0f0; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0in" vAlign=top width=213&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt" class=MsoNormal&gt;&lt;SPAN style="COLOR: black; FONT-SIZE: 9pt; mso-themecolor: text1; mso-themeshade: 191"&gt;&lt;FONT face=Calibri&gt;Create a CancellationTokenSource and pass its Token to an API that creates a Task.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="mso-yfti-irow: 2"&gt;
&lt;TD style="BORDER-BOTTOM: #f0f0f0; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0in; PADDING-LEFT: 5.4pt; WIDTH: 159.6pt; PADDING-RIGHT: 5.4pt; BACKGROUND: #bfbfbf; BORDER-TOP: #f0f0f0; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0in; mso-background-themecolor: text1; mso-background-themetint: 63" vAlign=top width=213&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-yfti-cnfc: 68" class=MsoNormal&gt;&lt;SPAN style="COLOR: black; FONT-SIZE: 9pt; mso-bidi-font-weight: bold; mso-themecolor: text1; mso-themeshade: 191"&gt;&lt;FONT face=Calibri&gt;To check if cancellation has been requested&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style="BORDER-BOTTOM: #f0f0f0; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0in; PADDING-LEFT: 5.4pt; WIDTH: 159.6pt; PADDING-RIGHT: 5.4pt; BACKGROUND: #bfbfbf; BORDER-TOP: #f0f0f0; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0in; mso-background-themecolor: text1; mso-background-themetint: 63" vAlign=top width=213&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-yfti-cnfc: 64" class=MsoNormal&gt;&lt;SPAN style="COLOR: black; FONT-SIZE: 9pt; mso-themecolor: text1; mso-themeshade: 191"&gt;&lt;FONT face=Calibri&gt;Check the IsCancellationRequested property on the relevant Task&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style="BORDER-BOTTOM: #f0f0f0; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0in; PADDING-LEFT: 5.4pt; WIDTH: 159.6pt; PADDING-RIGHT: 5.4pt; BACKGROUND: #bfbfbf; BORDER-TOP: #f0f0f0; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0in; mso-background-themecolor: text1; mso-background-themetint: 63" vAlign=top width=213&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-yfti-cnfc: 64" class=MsoNormal&gt;&lt;SPAN style="COLOR: black; FONT-SIZE: 9pt; mso-themecolor: text1; mso-themeshade: 191"&gt;&lt;FONT face=Calibri&gt;Check the IsCancellationRequested property on the CancellationToken that was passed to the API that created the Task&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="mso-yfti-irow: 3"&gt;
&lt;TD style="BORDER-BOTTOM: #f0f0f0; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0in; BACKGROUND-COLOR: transparent; PADDING-LEFT: 5.4pt; WIDTH: 159.6pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: #f0f0f0; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0in" vAlign=top width=213&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-yfti-cnfc: 4" class=MsoNormal&gt;&lt;SPAN style="COLOR: black; FONT-SIZE: 9pt; mso-bidi-font-weight: bold; mso-themecolor: text1; mso-themeshade: 191"&gt;&lt;FONT face=Calibri&gt;To acknowledge cancellation&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style="BORDER-BOTTOM: #f0f0f0; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0in; BACKGROUND-COLOR: transparent; PADDING-LEFT: 5.4pt; WIDTH: 159.6pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: #f0f0f0; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0in" vAlign=top width=213&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt" class=MsoNormal&gt;&lt;SPAN style="COLOR: black; FONT-SIZE: 9pt; mso-themecolor: text1; mso-themeshade: 191"&gt;&lt;FONT face=Calibri&gt;Check to ensure that IsCancellationRequested is true, then call the AcknowledgeCancellation() method on the relevant Task&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style="BORDER-BOTTOM: #f0f0f0; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0in; BACKGROUND-COLOR: transparent; PADDING-LEFT: 5.4pt; WIDTH: 159.6pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: #f0f0f0; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0in" vAlign=top width=213&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt" class=MsoNormal&gt;&lt;SPAN style="COLOR: black; FONT-SIZE: 9pt; mso-themecolor: text1; mso-themeshade: 191"&gt;&lt;FONT face=Calibri&gt;Throw an OperationCanceledException with the task’s CancellationToken&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR style="mso-yfti-irow: 4; mso-yfti-lastrow: yes"&gt;
&lt;TD style="BORDER-BOTTOM: black 1pt solid; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0in; PADDING-LEFT: 5.4pt; WIDTH: 159.6pt; PADDING-RIGHT: 5.4pt; BACKGROUND: #bfbfbf; BORDER-TOP: #f0f0f0; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0in; mso-border-bottom-themecolor: text1; mso-background-themecolor: text1; mso-background-themetint: 63" vAlign=top width=213&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-yfti-cnfc: 68" class=MsoNormal&gt;&lt;SPAN style="COLOR: black; FONT-SIZE: 9pt; mso-bidi-font-weight: bold; mso-themecolor: text1; mso-themeshade: 191"&gt;&lt;FONT face=Calibri&gt;To cancel a tree of tasks&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style="BORDER-BOTTOM: black 1pt solid; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0in; PADDING-LEFT: 5.4pt; WIDTH: 159.6pt; PADDING-RIGHT: 5.4pt; BACKGROUND: #bfbfbf; BORDER-TOP: #f0f0f0; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0in; mso-border-bottom-themecolor: text1; mso-background-themecolor: text1; mso-background-themetint: 63" vAlign=top width=213&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-yfti-cnfc: 64" class=MsoNormal&gt;&lt;SPAN style="COLOR: black; FONT-SIZE: 9pt; mso-themecolor: text1; mso-themeshade: 191"&gt;&lt;FONT face=Calibri&gt;Create all of the tasks as attached tasks and with the RespectParentCancellation flag set, then cancel the root task.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD style="BORDER-BOTTOM: black 1pt solid; BORDER-LEFT: #f0f0f0; PADDING-BOTTOM: 0in; PADDING-LEFT: 5.4pt; WIDTH: 159.6pt; PADDING-RIGHT: 5.4pt; BACKGROUND: #bfbfbf; BORDER-TOP: #f0f0f0; BORDER-RIGHT: #f0f0f0; PADDING-TOP: 0in; mso-border-bottom-themecolor: text1; mso-background-themecolor: text1; mso-background-themetint: 63" vAlign=top width=213&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-yfti-cnfc: 64" class=MsoNormal&gt;&lt;SPAN style="COLOR: black; FONT-SIZE: 9pt; mso-themecolor: text1; mso-themeshade: 191"&gt;&lt;FONT face=Calibri&gt;Pass the same CancellationToken to all Tasks, then cancel the associated CancellationTokenSource&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;o:p&gt;&lt;FONT size=3 face=Calibri&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;To see how this all works, let’s rewrite the code above for Beta 2.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;CancellationTokenSource cts = new CancellationTokenSource();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;CancellationToken token = cts.Token;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;Task myTask = Task.Factory.StartNew(() =&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;for (; ; )&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;token.ThrowIfCancellationRequested();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;...&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;}, token);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;// Elsewhere.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;cts.Cancel();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;A CancellationTokenSource (cts) is initialized, and a CancellationToken (token) is initialized to cts’s Token.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;myTask still loops indefinitely, but now it calls ThrowIfCancellationRequested.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This method just checks the IsCancellationRequested property on a CancellationToken.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;If true, it throws&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;an OperationCanceledException(token), which is the way to acknowledge cancellation in the new model.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Elsewhere, Cancel is called on cts to request cancellation on myTask.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;The new model addresses all of the problems with the old model listed above:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 0pt 0.5in; mso-list: l2 level1 lfo3" class=MsoListParagraphCxSpFirst&gt;&lt;SPAN style="mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3 face=Calibri&gt;1.&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;No more Task.Current (Task.Parent was removed too, as it could be used to get at the current Task).&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 0pt 0.5in; mso-list: l2 level1 lfo3" class=MsoListParagraphCxSpMiddle&gt;&lt;SPAN style="mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3 face=Calibri&gt;2.&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;The ability to check for cancellation requests may now be separated from the ability to request cancellation.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;If only the former is desired, grant access to the CancellationToken only.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 10pt 0.5in; mso-list: l2 level1 lfo3" class=MsoListParagraphCxSpLast&gt;&lt;SPAN style="mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3 face=Calibri&gt;3.&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;TPL now uses the new .NET 4 cancellation types.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;You can use the same CancellationToken{Source} to effect cancellation on multiple Tasks, Parallel.For calls, PLINQ queries, and more, all at once.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This provides both better composition and better performance.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Finally, there are other advantages to this model.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;One is that it is much easier to organize cancellation sets within a large nest of Tasks; just create the right number of tokens and pass them around accordingly.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Before, this scenario would have required tedious bookkeeping of many Task references and/or careful architecting of cancellation chains using TaskCreationOptions.RespectParentCancellation.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;That’s it for now.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The next post in the series will discuss a change regarding Tasks and parent/child relationships.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9909371" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/.NET+4.0/default.aspx">.NET 4.0</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Beta/default.aspx">Beta</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Cancellation/default.aspx">Cancellation</category></item><item><title>.NET 4 Beta 2 is here!</title><link>http://blogs.msdn.com/pfxteam/archive/2009/10/19/9909320.aspx</link><pubDate>Mon, 19 Oct 2009 18:50:05 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9909320</guid><dc:creator>toub</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/9909320.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=9909320</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=9909320</wfw:comment><description>&lt;p&gt;The .NET Framework 4 Beta 2 is now available! &lt;/p&gt;  &lt;p&gt;MSDN Subscribers can download it today, and it will be generally available for download on Wednesday.&amp;#160; More information is available at &lt;a title="http://msdn.microsoft.com/en-us/vstudio/dd582936.aspx" href="http://msdn.microsoft.com/en-us/vstudio/dd582936.aspx"&gt;http://msdn.microsoft.com/en-us/vstudio/dd582936.aspx&lt;/a&gt;.&amp;#160; Additionally, one of the really exciting things about this Beta release is that it’s “go-live”; more information on that is available at &lt;a title="“Going live” with Visual Studio 2010 Beta 2" href="http://blogs.msdn.com/jeffbe/archive/2009/10/19/going-live-with-visual-studio-2010-beta-2.aspx"&gt;“Going live” with Visual Studio 2010 Beta 2&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;As part of .NET 4 Beta 2, of course, comes improved parallelism support.&amp;#160; In the coming days and weeks, we’ll be blogging here about some of the exciting updates and additions in this release.&amp;#160; Stay tuned…&lt;/p&gt;  &lt;p&gt;In the meantime, the MSDN documentation on .NET 4’s parallelism support has been updated.&amp;#160; It’s a great place to start learning about all of the functionality available in this release.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/dd460693(VS.100).aspx"&gt;Parallel Programming in the .NET Framework&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;Namespaces&lt;/li&gt;    &lt;ul&gt;     &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system(VS.100).aspx"&gt;System&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system.collections.concurrent(VS.100).aspx"&gt;System.Collections.Concurrent&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system.linq(VS.100).aspx"&gt;System.Linq&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system.threading(VS.100).aspx"&gt;System.Threading&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system.threading.tasks(VS.100).aspx"&gt;System.Threading.Tasks&lt;/a&gt;&lt;/li&gt;   &lt;/ul&gt; &lt;/ul&gt;  &lt;p&gt;You can also learn more about the tools in Visual Studio 2010 for parallel development in the documentation at:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/dd537632(VS.100).aspx"&gt;Concurrency Visualizer&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/dd554943(VS.100).aspx"&gt;Parallel Stacks and Parallel Tasks Walkthrough&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Enjoy!&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9909320" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Release/default.aspx">Release</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Visual+Studio+2010/default.aspx">Visual Studio 2010</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/.NET+4.0/default.aspx">.NET 4.0</category></item><item><title>Parallel Computing Presentations in Michigan, Ohio, Kentucky, and Tennessee</title><link>http://blogs.msdn.com/pfxteam/archive/2009/10/16/9908240.aspx</link><pubDate>Fri, 16 Oct 2009 15:49:29 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9908240</guid><dc:creator>toub</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/9908240.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=9908240</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=9908240</wfw:comment><description>&lt;p&gt;In a week, I’m going to be traveling through Michigan, Ohio, Kentucky, and Tennessee, speaking about parallel computing, Visual Studio 2010, and .NET 4, primarily at corporations during the day and at user groups in the evenings.&lt;/p&gt;  &lt;p&gt;If you’re in the area and interested, please do attend, and I look forward to meeting you!&amp;#160; A list of events is available at &lt;a title="http://blogs.msdn.com/jennifer/archive/2009/10/14/stephen-toub-parallel-computing-tour.aspx" href="http://blogs.msdn.com/jennifer/archive/2009/10/14/stephen-toub-parallel-computing-tour.aspx"&gt;http://blogs.msdn.com/jennifer/archive/2009/10/14/stephen-toub-parallel-computing-tour.aspx&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;See you in a week!&lt;/p&gt;  &lt;p&gt;Stephen&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9908240" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Talks/default.aspx">Talks</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Visual+Studio+2010/default.aspx">Visual Studio 2010</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/.NET+4.0/default.aspx">.NET 4.0</category></item><item><title>Parallelized Map and Filter Operations</title><link>http://blogs.msdn.com/pfxteam/archive/2009/10/12/9906180.aspx</link><pubDate>Mon, 12 Oct 2009 16:03:38 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9906180</guid><dc:creator>toub</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/9906180.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=9906180</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=9906180</wfw:comment><description>&lt;p&gt;Common operations like map and filter are available in parallelized form through PLINQ, though the names differ.&amp;#160; A map can be achieved with PLINQ’s Select operator, and a filter with PLINQ’s Where operator.&lt;/p&gt;  &lt;p&gt;For example, I could implement a ParallelMap operation that takes in one array and returns another as follows:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;public static TOutput [] ParallelMap&amp;lt;TInput,TOutput&amp;gt;(     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; TInput [] input, Func&amp;lt;TInput,TOutput&amp;gt; map)      &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; return input.AsParallel().Select(map).ToArray();      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;and a ParallelFilter operation could be implemented in a similar fashion, based on PLINQ’s Where operator:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;public static TInput [] ParallelFilter&amp;lt;TInput&amp;gt;(     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; TInput [] input, Func&amp;lt;TInput,Boolean&amp;gt; filter)      &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; return input.AsParallel().Where(filter).ToArray();      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;In general, PLINQ is the recommended way to achieve such parallelization.&amp;#160; Not only is it useful for individual operations like this, but it’s also a great way to compose operations.&amp;#160; For example, if I wanted to write a ParallelFilterAndMap, I could achieve that as follows:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;public static TOutput [] ParallelFilterAndMap&amp;lt;TInput,TOutput&amp;gt;(     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; TInput [] input, Func&amp;lt;TInput,Boolean&amp;gt; filter, Func&amp;lt;TInput,TOutput&amp;gt; map)      &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; return input.AsParallel().Where(filter).Select(map).ToArray();      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;It is also possible to build such operations on top of Parallel.*.&amp;#160; For example, here’s ParallelMap re-implemented in terms of Parallel.For:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;public static TOutput [] ParallelMap&amp;lt;TInput,TOutput&amp;gt;(     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; TInput [] input, Func&amp;lt;TInput,TOutput&amp;gt; map)      &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; var output = new TOutput[input.Length];      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Parallel.For(0, input.Length, i =&amp;gt; output[i] = map(input[i]));      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; return output;      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;and ParallelFilterAndMap re-implemented in terms of Parallel.ForEach and ConcurrentBag&amp;lt;T&amp;gt;:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;public static TInput [] ParallelFilterAndMap&amp;lt;TInput,TOutput&amp;gt;(     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; TInput [] input, Func&amp;lt;TInput,Boolean&amp;gt; filter, Func&amp;lt;TInput,TOutput&amp;gt; map)      &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; var output = new ConcurrentBag&amp;lt;T&amp;gt;();      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Parallel.ForEach(input, item =&amp;gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (filter(item)) output.Add(map(item));      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; });      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; return output.ToArray();      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;As mentioned, in most cases you’re better off using PLINQ for these kinds of operations.&amp;#160; However, there may be cases where a Parallel.*-based version is best.&amp;#160; For example, let’s say that you wanted to implement an in-place parallel map operation, e.g. a map operation that maps from TData to TData, and that stores the new output into the input array.&amp;#160; PLINQ doesn’t modify the input data source, so if you wanted that functionality, you could build it on top of Parallel.For:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;public static void ParallelMap&amp;lt;TData&amp;gt;(     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; TData [] data, Func&amp;lt;TData,TData&amp;gt; map)      &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Parallel.For(0, data.Length, i =&amp;gt; data[i] = map(data[i]));      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;There are a few other subtle differences that you could take advantage of by building on Parallel.For/ForEach instead of on PLINQ.&amp;#160; For example, PLINQ uses a static number of threads for the processing of a given query (which defaults to Environment.ProcessorCount), whereas the number of threads used by Parallel.* may vary over time as influenced by the ThreadPool’s thread injection and retirement logic.&amp;#160; Parallel.* can also be targeted to a specific and custom TaskScheduler, something not supported by PLINQ in .NET 4 (PLINQ always runs on TaskScheduler.Default, which is based on the .NET 4 ThreadPool).&lt;/p&gt;  &lt;p&gt;Happy coding.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9906180" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/PLINQ/default.aspx">PLINQ</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Code+Samples/default.aspx">Code Samples</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/.NET+4.0/default.aspx">.NET 4.0</category></item><item><title>TaskScheduler.FromCurrentSynchronizationContext</title><link>http://blogs.msdn.com/pfxteam/archive/2009/09/22/9898090.aspx</link><pubDate>Tue, 22 Sep 2009 19:46:13 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9898090</guid><dc:creator>toub</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/9898090.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=9898090</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=9898090</wfw:comment><description>&lt;p&gt;The Task abstractions in .NET 4 run on instances of the TaskScheduler class.&amp;#160; Two implementations of TaskScheduler ship as part of the .NET Framework 4.&amp;#160; The first is the default scheduler, which is integrated with the .NET 4 ThreadPool and takes advantage of its work-stealing queues.&amp;#160; The second is the type of TaskScheduler returned from the static method TaskScheduler.FromCurrentSynchronizationContext.&lt;/p&gt;  &lt;p&gt;According to MSDN, SynchronizationContext “provides the basic functionality for propagating a synchronization context in various synchronization models.”&amp;#160; What does that really mean?&amp;#160; At its core, SynchronizationContext provides two methods, Send and Post, both of which accept a delegate to be executed.&amp;#160; Send synchronously invokes the delegate, and Post asynchronously invokes the delegate.&amp;#160; That’s it, and the base implementation of SynchronizationContext doesn’t do anything fancier than that:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;public virtual void Send(SendOrPostCallback d, object state)     &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; d(state);      &lt;br /&gt;} &lt;/p&gt;    &lt;p&gt;public virtual void Post(SendOrPostCallback d, object state)     &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; ThreadPool.QueueUserWorkItem(new WaitCallback(d.Invoke), state);      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Where things get interesting is when new types are derived from SynchronizationContext, something typically done by a UI framework (though there are other non-UI framework implementations).&amp;#160; For folks familiar with Windows Forms and Windows Presentation Framework development, you’re likely aware that UI controls should only be accessed by the thread that created them, almost always the main UI thread.&amp;#160; Thus, if a thread doing work in the background wants to update something in the UI, it needs to marshal that work back to the GUI thread so that the controls may be accessed safely.&amp;#160; Different UI frameworks expose different ways for accomplishing this marshaling.&amp;#160; For example, in Windows Forms, one uses the Invoke or BeginInvoke method of the target Control (or at least a Control created on the same thread as the target Control).&amp;#160; In WPF, one uses the target thread’s Dispatcher and corresponding Invoke/BeginInvoke&amp;#160; methods.&amp;#160; With every UI framework having its own model for marshaling work to a particular “synchronization context”, it becomes difficult to write code that supports this marshaling concept but which is agnostic to the particular environment that it’s in.&amp;#160; Enter SynchronizationContext.&amp;#160; A new type may be derived from SynchronizationContext such that its Send method synchronously marshals a delegate to the right thread for execution, and Post does the same but asynchronously.&amp;#160; If you look at the implementations of the SynchronizationContexts provided by Windows Forms and WPF, that’s exactly what they do, delegating to the relevant Invoke/BeginInvoke methods from Send and Post to marshal the work correctly.&lt;/p&gt;  &lt;p&gt;To make it easy to get at the right SynchronizationContext, a UI framework like Windows Forms will publish an instance of its SynchronizationContext-derived class to SynchronizationContext.Current.&amp;#160; Code can then grab SynchronizationContext.Current and use it to marshal work, without having to know whether it’s being used from Windows Forms or Windows Presentation Foundation or another similar model.&lt;/p&gt;  &lt;p&gt;“TaskScheduler.FromCurrentSynchronizationContext” should now make more sense.&amp;#160; This method creates a TaskScheduler that wraps the SynchronizationContext returned from SynchronizationContext.Current.&amp;#160; Thus, this gives you a TaskScheduler that will execute Tasks on the current SynchronizationContext.&amp;#160; Why is that useful?&amp;#160; It means you can create Tasks that are able to access UI controls safely, simply by running them on the right scheduler.&amp;#160; &lt;/p&gt;  &lt;p&gt;Let’s say that I wanted to load three images from some data source.&amp;#160; When those images have been loaded, I want to blend them all together, and then I want to display the result into a PictureBox on my UI.&amp;#160; Using Tasks and TaskScheduler.FromCurrentSynchronizationContext, I could write code like the following:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;private void Button1_Click(…)     &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; var ui = TaskScheduler.FromCurrentSynchronizationContext();      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; var tf = Task.Factory;      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // Load the three images asynchronously      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; var imageOne = tf.StartNew(() =&amp;gt; LoadFirstImage());      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; var imageTwo = tf.StartNew(() =&amp;gt; LoadSecondImage());      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; var imageThree = tf.StartNew(() =&amp;gt; LoadThirdImage());      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // When they’ve been loaded, blend them      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; var blendedImage = tf.ContinueWhenAll(      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; new [] { imageOne, imageTwo, imageThree }, _ =&amp;gt;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; BlendImages(imageOne.Result, imageTwo.Result, imageThree.Result));      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // When we’re done blending, display the blended image      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; blendedImage.ContinueWith(_ =&amp;gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; pictureBox1.Image = blendedImage.Result;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }, ui);      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;This code runs three tasks to load the three input images asynchronously.&amp;#160; When all of those have been loaded, again asynchronously some BlendImages method is used to blend the images, taking the three inputs and returning the blended image.&amp;#160; Finally, once that’s done, another task is used to render the blended image by storing it into a PictureBox on the UI.&amp;#160; Since this modifies a UI control, we need to do it from the UI thread.&amp;#160; Thus, we pass a TaskScheduler to the ContinueWith method; this scheduler targets the UI’s SynchronizationContext, and will cause the Task to execute on the UI thread.&lt;/p&gt;  &lt;p&gt;TaskScheduler.FromCurrentSynchronizationContext is provided for convenience and because this is a very common need.&amp;#160; However, due to TaskScheduler’s extensibility, it’s actually possible to implement this behavior yourself, and in doing so you could modify it to suit your own needs however you see fit.&lt;/p&gt;  &lt;p&gt;Let’s say you did want to develop a new SynchronizationContextTaskScheduler.&amp;#160; It might look something like this:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;public class SynchronizationContextTaskScheduler : TaskScheduler     &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; private ConcurrentQueue&amp;lt;Task&amp;gt; _tasks = new ConcurrentQueue&amp;lt;Task&amp;gt;();      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; private SynchronizationContext _context;&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public SynchronizationContextTaskScheduler() :      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; this(SynchronizationContext.Current) { } &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public SynchronizationContextTaskScheduler(     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; SynchronizationContext context)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (context == null) throw new ArgumentNullException(&amp;quot;context&amp;quot;);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _context = context;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; } &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; protected override void QueueTask(Task task)     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // Add the task to the collection      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _tasks.Enqueue(task);      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // Queue up a delegate that will dequeue and execute a task      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _context.Post(delegate      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Task toExecute;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (_tasks.TryDequeue(out toExecute)) TryExecuteTask(toExecute);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }, null);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; } &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; protected override bool TryExecuteTaskInline(     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Task task, bool taskWasPreviouslyQueued)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return SynchronizationContext.Current == _context &amp;amp;&amp;amp;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; TryExecuteTask(task);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; } &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; public override int MaximumConcurrencyLevel { get { return 1; } } &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; protected override IEnumerable&amp;lt;Task&amp;gt; GetScheduledTasks()     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return _tasks.ToArray();      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Not a lot of code for a fairly powerful thing.&amp;#160; &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;The constructors simply accept the target SynchronizationContext and store it, also initializing a thread-safe queue that will store the tasks to be executed.&amp;#160; &lt;/li&gt;    &lt;li&gt;The QueueTask method is called whenever the system is providing a Task for this scheduler to execute: this scheduler handles it by storing that Task into a queue, and then Post’ing to the SynchronizationContext a delegate that will pull the next Task from the queue and execute it.&amp;#160; &lt;/li&gt;    &lt;li&gt;The TryExecuteTaskInline is invoked any time the system wants to run a Task inline on the current thread (either from a call to RunSynchronously or from a Wait attempt): we need to make sure that the call is coming from the same SynchronizationContext as the target, otherwise we may end up running in the wrong context.&lt;/li&gt;    &lt;li&gt;We only intended to support SynchronizationContexts that represent a single thread of execution (that’s most common), so we return 1 from MaximumConcurrencyLevel.&lt;/li&gt;    &lt;li&gt;And we want the debugger to be able to display tasks scheduled to this scheduler, so we override GetScheduledTasks to return an array of the tasks queued. (This is why we need to explicitly store the queue of tasks; otherwise, we could have simply relied on lambda closures to capture each task to be executed.)&lt;/li&gt; &lt;/ul&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9898090" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/ThreadPool/default.aspx">ThreadPool</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Code+Samples/default.aspx">Code Samples</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Visual+Studio+2010/default.aspx">Visual Studio 2010</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/.NET+4.0/default.aspx">.NET 4.0</category></item><item><title>The meaning of TaskStatus</title><link>http://blogs.msdn.com/pfxteam/archive/2009/08/30/9889070.aspx</link><pubDate>Sun, 30 Aug 2009 10:35:40 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9889070</guid><dc:creator>toub</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/9889070.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=9889070</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=9889070</wfw:comment><description>&lt;p&gt;Every System.Threading.Tasks.Task instance goes through a lifecycle, and it only makes this journey once.&amp;#160; To provide insight into where in that lifecycle a given Task is, the Task class provides an instance Status property.&amp;#160; That property returns a value from the TaskStatus enumeration that reflects the current point in the lifecycle.&lt;/p&gt;  &lt;p&gt;“Current” is the operative word here.&amp;#160; Many of the states are transient, meaning that we’re dealing with a concurrent system, and by the time you’ve received the value of the status, the status may have changed.&amp;#160; However, the lifecycle does not contain cycles (as ironic as that may sound), meaning that there’s a directionality to the various states, and once a given state has been reached, the Task won’t return back to that state again or to any that came before it.&amp;#160; Additionally, there are three “final” states, where once in those states, the Task is no longer executing and will no longer change state.&lt;/p&gt;  &lt;p&gt;Here are the states and an informal description of what they imply:   &lt;br /&gt;&lt;/p&gt;  &lt;table border="1" cellspacing="0" cellpadding="2" width="511"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="127"&gt;&lt;strong&gt;TaskStatus Enumeration Value&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="382"&gt;&lt;strong&gt;Informal Description&lt;/strong&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="127"&gt;Created&lt;/td&gt;        &lt;td valign="top" width="382"&gt;This is the starting state for tasks created through a Task constructor.&amp;#160; Tasks in this state will not leave the state until Start or RunSynchronously is called on the instance or until the Task is canceled.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="127"&gt;WaitingForActivation&lt;/td&gt;        &lt;td valign="top" width="382"&gt;This is the starting state for tasks created through methods like ContinueWith, ContinueWhenAll, ContinueWhenAny, and FromAsync, as well as from a TaskCompletionSource&amp;lt;TResult&amp;gt;.&amp;#160; The task isn’t currently scheduled, and won’t be until some dependent operation has completed (some tasks may never be scheduled, such as those created by a TaskCompletionSource&amp;lt;TResult&amp;gt; that have nothing relevant to be scheduled).&amp;#160; For example, a task created by ContinueWith won’t be scheduled until the antecedent task (the one off of which ContinueWith was called) completes execution.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="127"&gt;WaitingToRun&lt;/td&gt;        &lt;td valign="top" width="382"&gt;The task has been scheduled to a TaskScheduler and is waiting to be picked up by that scheduler and run.&amp;#160; This is the starting state for tasks created through TaskFactory.StartNew; by the time the Task is returned from StartNew, it will already have been scheduled, and thus the state will be at least WaitingToRun (“at least”, since by the time StartNew returns, the Task could of course have already started or even completed executing).&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="127"&gt;Running&lt;/td&gt;        &lt;td valign="top" width="382"&gt;The Task is currently executing.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="127"&gt;WaitingForChildrenToComplete&lt;/td&gt;        &lt;td valign="top" width="382"&gt;A Task isn’t considered complete until its attached children have completed.&amp;#160; If a Task has finished executing its code body, it will leave the Running state, and if it’s then implicitly waiting for its children to complete, it will enter this state.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="127"&gt;RanToCompletion&lt;/td&gt;        &lt;td valign="top" width="382"&gt;One of the three final states.&amp;#160; A Task in this state has successfully completed execution, running to the end of its body without cancellation and without throwing an unhandled exception.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="127"&gt;Canceled&lt;/td&gt;        &lt;td valign="top" width="382"&gt;One of the three final states.&amp;#160; A Task in this state completed execution, but it did so through cancellation.&amp;#160; To end in the Canceled state, a Task must either have cancellation requested prior to starting execution, or it must acknowledge a cancellation request during its execution.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="127"&gt;Faulted&lt;/td&gt;        &lt;td valign="top" width="382"&gt;One of the three final states.&amp;#160; A Task in this state completed execution due to an unhandled exception in its body or due to one of its attached children completing in this state.&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;Several of these status values are also communicated through helper properties on the Task class.&amp;#160; For a Task t:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;t.IsCanceled returns true if and only if t.Status equals TaskStatus.Canceled.&amp;#160; &lt;/li&gt;    &lt;li&gt;t.IsFaulted returns true if and only if t.Status equals TaskStatus.Faulted.&amp;#160; Additionally, t.Exception will be non-null if and only if t.IsFaulted is true.&lt;/li&gt;    &lt;li&gt;t.IsCompleted returns true if and only if t.Status equals TaskStatus.RanToCompletion, TaskStatus.Canceled, or TaskStatus.Faulted (i.e. one of the three final states). Note that IsCompleted does not just correspond to RanToCompletion, but rather to all final states.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Several operations in the Task Parallel Library are tied to the concept of a final state, or more generally to IsCompleted.&amp;#160; For example, a call to the Wait method on a Task will not return until that Task’s IsCompleted is true.&amp;#160; And the continuations for a Task will not fire until that same condition is met.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9889070" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/.NET+4.0/default.aspx">.NET 4.0</category></item><item><title>Parallel Extensions and I/O</title><link>http://blogs.msdn.com/pfxteam/archive/2009/08/04/9857477.aspx</link><pubDate>Wed, 05 Aug 2009 00:55:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9857477</guid><dc:creator>dashih</dc:creator><slash:comments>8</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/9857477.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=9857477</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=9857477</wfw:comment><description>&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;In this post, we’ll investigate some ways that Parallel Extensions can be used to introduce parallelism and asynchrony to I/O scenarios.&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Here’s a simple scenario. &lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/SPAN&gt;I want to retrieve data from a number of web resources.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;static string[] Resources = new string[]&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;"http://www.microsoft.com", "http://www.msdn.com",&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;"http://www.msn.com", "http://www.bing.com"&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;};&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Using the WebClient class, I might end up with the following.&lt;SPAN style="LINE-HEIGHT: 115%; FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;var data = new List&amp;lt;byte[]&amp;gt;();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;var wc = new WebClient();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;foreach (string resource in Resources)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;data.Add(wc.DownloadData(resource));&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;// Use the data.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 1in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;However, these days, downloading data from the web usually utilizes only a small fraction of my available bandwidth.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;So there are potential performance gains here, and with TPL’s parallel ForEach loop, they are easily had.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;var data = new ConcurrentBag&amp;lt;byte[]&amp;gt;();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;Parallel.ForEach(Resources, resource =&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;data.Add((new WebClient()).DownloadData(resource));&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;});&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;// Use the data.&lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Note that WebClient instances do not support multiple pending asynchronous operations (and the class is not thread-safe), so I need a separate instance for each operation.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Also, since the normal BCL collections (List&amp;lt;T&amp;gt;, etc.) are not thread-safe, I need something like ConcurrentBag&amp;lt;T&amp;gt; to store the results.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Of course, storing all the data in a collection assumes the scenario requires that all retrieval operations complete before processing.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;If this was not the case, I could start processing each data chunk right after obtaining it right in the loop, exploiting more parallelism.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;However, for the purposes of this investigation, I wanted to determine the possible performance gains in the absence of CPU-intensive work.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;As it turns out, the above often yields linear speedup against sequential, with some variation due to the inconsistent nature of web site response times.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;And it was pretty straightforward.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;However, things would have been even easier had I started out with a “LINQ” frame of mind.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;First, I can convert my original sequential code to a LINQ query.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Then, I can turn it into PLINQ using the AsParallel method and use WithDegreeOfParallelism to control the number of concurrent retrievals.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;var data =&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;from resource in Resources&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;.AsParallel()&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;.WithDegreeOfParallelism(numConcurrentRetrievals)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;select (new WebClient()).DownloadData(resource);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;// Sometime later...&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;foreach (byte[] result in data) { }&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;(As an aside, it’s worth noting that WithDegreeOfParallelism causes PLINQ to use &lt;I style="mso-bidi-font-style: normal"&gt;exactly&lt;/I&gt; numConcurrentRetrivals Tasks.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This differs from the MaxDegreeOfParallelism option that I could have used with my previous Parallel.ForEach code, because that option sets the &lt;I style="mso-bidi-font-style: normal"&gt;maximum&lt;/I&gt;; the actual number of threads still depends on the ThreadPool’s thread-adjusting logic.)&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;This code offers enhanced readability and makes storing the data easier.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In addition, I can continue on the main thread, as PLINQ queries do not execute until the data they represent is accessed – that is, when MoveNext is called on the relevant enumerator.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;However, in this particular case, I don’t want to delay my query’s execution until I need the data; I actually want to execute my query &lt;I style="mso-bidi-font-style: normal"&gt;while&lt;/I&gt; continuing on the main thread.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;To do so, I can wrap my query in a Task and force its immediate execution using ToArray.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;var t = Task.Factory.StartNew(() =&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;return&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;from resource in Resources&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;.AsParallel()&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;.WithDegreeOfParallelism(numConcurrentRetrievals)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;select (new WebClient()).DownloadData(resource).ToArray();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;});&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;// Sometime later...&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;foreach (byte[] result in t.Result) { }&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;// OR, use a continuation&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;t.ContinueWith(dataTask =&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;foreach (byte[] result in dataTask.Result) { }&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;});&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Now, I’ve got asynchrony, and I still get similar speedup.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;However, there’s still something about this code that is not ideal.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The work (sending off download requests and blocking) requires almost no CPU, but it is being done by ThreadPool threads since I’m using the default scheduler.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Ideally, threads should only be used for CPU-bound work (when there’s actually work to do).&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Of course, this probably won’t matter much for most typical client applications, but in scenarios where resources are tight, it could be a serious issue.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Therefore, it’s worth investigating how we might reduce the number of blocked threads, perhaps by not using threads at all where possible.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3 face=Calibri&gt;To achieve this, I’ll be using ideas from a previous post: &lt;/FONT&gt;&lt;A href="http://blogs.msdn.com/pfxteam/archive/2009/06/19/9791857.aspx" mce_href="http://blogs.msdn.com/pfxteam/archive/2009/06/19/9791857.aspx"&gt;&lt;FONT size=3 face=Calibri&gt;Tasks and the Event-based Asynchronous Pattern&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3 face=Calibri&gt;.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;That article explained how to create a Task&amp;lt;TResult&amp;gt; from any type that implements the EAP, and it presented an extension method for WebClient (available along with many others in the &lt;/FONT&gt;&lt;A href="http://code.msdn.microsoft.com/ParExtSamples" mce_href="http://code.msdn.microsoft.com/ParExtSamples"&gt;&lt;FONT size=3 face=Calibri&gt;ParallelExtensionsExtras&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;):&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;public static Task&amp;lt;byte[]&amp;gt; DownloadDataTask(&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;this WebClient webClient, Uri address);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;The key point is that this method produces a Task&amp;lt;TResult&amp;gt; by integrating WebClient’s EAP implementation with a TaskCompletionSource&amp;lt;TResult&amp;gt;, and I can use it to rewrite my scenario.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;var tasks = new Queue&amp;lt;Task&amp;lt;byte[]&amp;gt;&amp;gt;();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;foreach (string resource in Resources)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;WebClient wc = new WebClient();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;tasks.Enqueue(wc.DownloadDataTask(new Uri(resource)));&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;// Sometime later...&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;while (tasks.Count &amp;gt; 0)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/SPAN&gt;byte[] result = tasks.Dequeue().Result;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;// OR, use a continuation&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;Task&amp;lt;byte[]&amp;gt;.Factory.ContinueWhenAll(tasks.ToArray(), dataTasks =&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;foreach (var dataTask in dataTasks) &lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;{&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;byte[] result = dataTask.Result;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;});&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none" class=MsoNormal&gt;&lt;SPAN style="FONT-FAMILY: Consolas; FONT-SIZE: 9pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;With this, I’ve got a solution that uses parallelism for speed-up, is asynchronous, and does not burn more threads than necessary!&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN: 0in 0in 10pt" class=MsoNormal&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;To recap, in this post, we considered a typical I/O scenario.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;First, we saw how easy it was to arrive at solutions that are better than the sequential one.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Then, we delved deeper to discover a more complex solution (integrating EAP with Tasks) that offers even more benefits.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9857477" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/pfxteam/attachment/9857477.ashx" length="20062" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/pfxteam/archive/tags/PLINQ/default.aspx">PLINQ</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/.NET+4.0/default.aspx">.NET 4.0</category></item><item><title>TaskCreationOptions.PreferFairness</title><link>http://blogs.msdn.com/pfxteam/archive/2009/07/07/9822857.aspx</link><pubDate>Tue, 07 Jul 2009 19:08:38 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9822857</guid><dc:creator>toub</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/9822857.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=9822857</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=9822857</wfw:comment><description>&lt;p&gt;One of the ways in which the Task Parallel Library achieves good performance is through “work-stealing”.&amp;#160; Work-stealing is supported in the &lt;a href="http://blogs.msdn.com/ericeil/archive/2009/04/23/clr-4-0-threadpool-improvements-part-1.aspx"&gt;.NET 4 ThreadPool&lt;/a&gt; for access through the Task Parallel Library and its default scheduler.&amp;#160; This manifests as every thread in the ThreadPool having its own queue for work; when that thread creates Tasks, by default these tasks are enqueued into the thread’s local queue, rather than into the global queue that a call to ThreadPool.QueueUserWorkItem would typically target.&amp;#160; When a thread goes in search for work to be executed, it starts with its local queue, an operation which enable some extra efficiencies due to improved cache locality, minimized contention, and so forth.&amp;#160; However, this logic also affects fairness.&lt;/p&gt;  &lt;p&gt;A typical thread pool will have a single queue that maintains all of the work to be executed.&amp;#160; When threads in the pool are ready to process another work item, they’ll dequeue the work from the head of the queue, and when new work arrives to be executed by the pool, it’ll be enqueued onto the queue’s tail.&amp;#160; This provides a level of fairness between work items, in that work items that arrive first are more likely to be picked off and start executing first.&lt;/p&gt;  &lt;p&gt;Work-stealing perturbs that fairness.&amp;#160; Threads external to the pool could be queuing up work, but if the threads in the pool are also generating work, the work generated by the pool will be preferred over the other work items, based on the search order employed by the threads in the pool (which start searching for work first with their local queues, only proceeding on to the global queue and then on to other threads’ queues if work wasn’t available locally).&amp;#160; This behavior is typically expected and even desired, in that if a work item being executed is generating more work, that generated work is typically considered part of the overall operation being processed, and thus it makes sense it would be preferred over other unrelated work.&amp;#160; For example, imagine a quicksort operation, where each recursive sort invocation potentially results in several further recursive calls; those calls, which in a parallel implementation are likely individual tasks, are part of the all-up sort operation.&lt;/p&gt;  &lt;p&gt;Still, there are some scenarios where this default behavior is inappropriate, where fairness should be maintained between particular work items generated by threads in the pool and work items generated by other threads.&amp;#160; This is often the case for long chains of continuations, where the work generated isn’t considered part of the current work but rather a follow-on to the current work.&amp;#160; In those cases, you may want that follow-on work to be prioritized in a fair manner with other work in the system.&amp;#160; This is where TaskCreationOptions.PreferFairness can prove useful.&lt;/p&gt;  &lt;p&gt;When a Task is scheduled to the default scheduler, the scheduler looks to see whether the current thread from which the Task is being queued is a ThreadPool thread that has its own local queue.&amp;#160; If it isn’t, the work item will be queued to the global queue.&amp;#160; If it is, the scheduler will also check whether the TaskCreationOptions value for the Task includes the PreferFairness flag, which is not on by default.&amp;#160; If the flag is set, even if the thread does have its own local queue, the scheduler will still enqueue the Task to the global queue rather than to the local queue.&amp;#160; In this manner, that Task will be considered fairly along with all other work items queued globally.&lt;/p&gt;  &lt;p&gt;What was just described is the current implementation of the PreferFairness flag in the default scheduler.&amp;#160; The implementation could of course change, but what won’t change is the purpose of the flag: by specifying PreferFairness, you’re telling the system that this Task shouldn’t be prioritized just because it’s coming from a local queue.&amp;#160; You’re telling the system that you want the system to do its best to ensure that this Task is prioritized in a first-come, first-serve nature.&lt;/p&gt;  &lt;p&gt;One other thing to note is that Task itself knows nothing of this flag; it’s just a flag set as an option on the Task.&amp;#160; It’s the scheduler that decides how it wants to handle this particular option, just as with TaskCreationOptions.LongRunning.&amp;#160; The default scheduler handles it as described above, but another scheduler (such as one you write) may do with this flag whatever it wants, including ignoring it.&amp;#160; Hence the naming “Prefer” rather than something stricter like “Guarantee”.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9822857" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/ThreadPool/default.aspx">ThreadPool</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/.NET+4.0/default.aspx">.NET 4.0</category></item><item><title>Asynchronous methods, C# iterators, and Tasks</title><link>http://blogs.msdn.com/pfxteam/archive/2009/06/30/9809774.aspx</link><pubDate>Tue, 30 Jun 2009 19:09:32 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9809774</guid><dc:creator>toub</dc:creator><slash:comments>21</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/9809774.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=9809774</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=9809774</wfw:comment><description>&lt;p&gt;More and more, developers are realizing the significant scalability advantages that asynchronous programming can provide, especially as it relates to I/O. &lt;/p&gt;  &lt;p&gt;Consider an application that needs to copy data from one stream to another stream, such as is being done in the following synchronous implementation:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;static void CopyStreamToStream(Stream input, Stream output)     &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // Buffer space for the data to be read and written      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; byte [] buffer = new byte[0x2000];      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // While there’s data to be read and written      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; while(true)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // Read data. If we weren’t able to read any, bail.      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // Otherwise, write it out and start over again.      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; int numRead = input.Read(buffer, 0, buffer.Length);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (numRead == 0) break;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; output.Write(buffer, 0, numRead);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;In many cases like this, such as if the Streams are FileStream instances representing files on disk, or NetworkStream instances representing remote data, the operations being performed require little-to-no computational power, as the majority of the time is spent waiting on the I/O subsystems and devices. If one such operation is being performed at a time, that waiting isn’t such a big deal. But in a synchronous implementation like the one above, that waiting ends up blocking a thread, rendering the thread useless to do anything else while waiting. Threads by default take up a sizeable chunk of memory as well as kernel resources. Thus, if multiple concurrent calls to CopyStreamToStream are executed, multiple threads may be wasted. Since threads consume a non-negligable amount of resources, we try to limit the number of threads in an application at any one time, such as by using a thread pool, and this synchronous style of programming I/O can lead to scalability bottlenecks, especially in server components where we desire to process as many user requests concurrently as the machine’s resources will possibly allow.&lt;/p&gt;  &lt;p&gt;One solution to this problem is through compiler support. A compiler could recognize this synchronous pattern and translate it into an asynchronous one. Such a transformation of that same snippet might look like the following (note that this is hand-generated and is not the actual output of any particular compiler, and rather is my attempt to write this out concisely while still human-understandable):&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;static void CopyStreamToStreamAsync(     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Stream input, Stream output, Action&amp;lt;Exception&amp;gt; completed)      &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // Buffer space for the data to be read and written      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; byte[] buffer = new byte[0x2000];      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // The read/write loop. The parameter is the IAsyncResult of the       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // last read operation that still need to be completed with a call       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // to EndRead. If the parameter is null, that means a new read needs       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // to be started.      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Action&amp;lt;IAsyncResult&amp;gt; readWriteLoop = null;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; readWriteLoop = iar =&amp;gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; try       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // Determine whether to start with a BeginRead or&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // an EndRead/BeginWrite, based on whether iar is null.      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // Then, as long as the loop continues, alternate between       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // reading and writing.      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; for (bool isRead = iar == null; ; isRead = !isRead)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; switch (isRead)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // Do BeginRead(...)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; case true:      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // Start the asynchronous read      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; iar = input.BeginRead(buffer, 0, buffer.Length, readResult =&amp;gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // If the read completed synchronously, immediately       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // return from the callback, as the processing of the       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // read will be handled synchronously      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // from the same thread that called BeginRead      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (readResult.CompletedSynchronously) return;      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // The read completed asynchronously, so we need&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // to run the processing loop,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // starting with EndRead/BeginWrite.      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; readWriteLoop(readResult);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }, null);      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // If the read is completing asynchronously, bail, as       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // there's nothing more to do.      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // If it completed synchronously, loop around to do       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // the EndRead/BeginWrite synchronously.      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (!iar.CompletedSynchronously) return;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; break;      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // Do BeginWrite(...)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; case false:      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // Complete the previous read. If there's no more data       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // to be read/written, bail.      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; int numRead = input.EndRead(iar);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (numRead == 0)       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; completed(null);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // Now that we know how much data was read, write it       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // out asynchronously      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; iar = output.BeginWrite(buffer, 0, numRead, writeResult =&amp;gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // If the write completed synchronously, allow       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // the thread that called BeginWrite      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // to handle it.      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (writeResult.CompletedSynchronously) return;      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // Otherwise, complete the asynchronous write       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // and launch the read/write loop      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // to continue all over again.      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; output.EndWrite(writeResult);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; readWriteLoop(null);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }, null);      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // If the write is completing asynchronously, bail,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // as there's nothing more to do.      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // Otherwise, complete the write synchronously and       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // loop around.      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (!iar.CompletedSynchronously) return;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; output.EndWrite(iar);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; break;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; } catch(Exception e) { completed(e); }      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; };      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // Start the whole process off with a read.      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; readWriteLoop(null);      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;a href="http://msdn.microsoft.com/en-us/devlabs/dd795202.aspx"&gt;The Axum compiler, available on DevLabs&lt;/a&gt;, is actually capable of these kinds of transformations for asynchronous programming, and you could imagine such functionality being baked into a mainstream language like C#. Here’s how the code could be written asynchronously with Axum:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;static asynchronous void CopyStreamToStream(Stream input, Stream output)     &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; byte [] buffer = new byte[0x2000];      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; while(true)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; int numRead = input.Read(buffer, 0, buffer.Length);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (numRead == 0) break;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; output.Write(buffer, 0, numRead);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;That’s quite lovely. Comparatively, the hand-written code is mind-numbing, and it’s not something you want to have to write each and every time you need to perform some kind of repeating operation like this asynchronously.&lt;/p&gt;  &lt;p&gt;As such, some developers have started to take advantage of C# iterators for writing asynchronous code. While not originally designed for this purpose, the compiler transformations employed for C# iterators are similar to what’s necessary for writing asynchronous code, and thus with a bit of library-based support, it’s possible to write an iterator that looks sequential but that takes advantage of asynchrony. Several libraries have been based on this approach, including the Concurrency &amp;amp; Coordination Runtime (CCR) from Microsoft Robotics, Jeffrey Richter’s AsyncEnumerator, and others.&lt;/p&gt;  &lt;p&gt;The key to taking advantage of this pattern is yielding something from an iterator that can invoke a callback when an operation completes. The pattern then becomes:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;IEnumerable&amp;lt;ThingThatHasCallbackWhenCompletes&amp;gt; AsyncMethod()     &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; ...      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; yield return SomethingThatReturnsThingThatHasCallbackWhenCompletes();      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; ... // code here executes when the&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // yielded ThingThatHasCallbackWhenCompletes completes      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The idea is that the iterator method returns an IEnumerable of instances that represent a piece of an asynchronous operation. A utility function is used to invoke the iterator method, and iterates over the resulting enumerator. Each time the utility function gets the next instance from the enumerator, it registers some code to monitor the operation for completion, and when the operation completes, it moves next on the enumerator. Moving next on the enumerator results in re-entering the iterator method at the code location after the last yield point, thus allowing another asynchronous operation to be yielded. In this fashion, the iterator method can in effect yield asynchronous operations, and by using “yield return” to instrument the code with those async points, you as the developer can write an asynchronous method in a manner that looks largely sequential.&lt;/p&gt;  &lt;p&gt;Now, think about the description above for the kind of object that needs to be yielded: “something that can invoke a callback when an operation completes.” Sound familiar? The System.Threading.Tasks.Task class in .NET 4 provides this exact functionality. A Task represents an asynchronous operation, and it has a ContinueWith method that enables a callback to be invoked when that asynchronous operation completes. Thus, we should be able to yield Task instances from an iterator in order to write an asynchronous method. Here’s the same CopyStreamToStream example implemented asynchronously in this fashion:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;static IEnumerable&amp;lt;Task&amp;gt; CopyStreamToStreamAsync(     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Stream input, Stream output)      &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // Buffer space for the data to be read and written      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; byte [] buffer = new byte[0x2000];      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // While there’s data to be read and written      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; while(true)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // Read data asynchronously. When the operation completes,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // if no data could be read, we’re done.      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; var read = Task&amp;lt;int&amp;gt;.Factory.FromAsync(      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; input.BeginRead, input.EndRead, buffer, 0, buffer.Length, null,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; TaskCreationOptions.DetachedFromParent);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; yield return read;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (read.Result == 0) break;      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // Write the data asynchronously      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; yield return Task.Factory.FromAsync(      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; output.BeginWrite, output.EndWrite, buffer, 0, read.Result, null,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; TaskCreationOptions.DetachedFromParent);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Much simpler. Where we were previously doing synchronous reads and writes, now we’re yielding the result of calling the built-in Task.Factory.FromAsync method, which creates Tasks that represent asynchronous reads and writes following the APM pattern. We could of course simplify this code further by using a few helper extension methods to hide some of the asynchronous details (these helpers are part of the Beta 1 samples at &lt;a title="http://code.msdn.microsoft.com/ParExtSamples" href="http://code.msdn.microsoft.com/ParExtSamples"&gt;http://code.msdn.microsoft.com/ParExtSamples&lt;/a&gt;):&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;public static Task&amp;lt;int&amp;gt; ReadTask(this Stream stream,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; byte [] buffer, int offset, int count)      &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; return Task&amp;lt;int&amp;gt;.Factory.FromAsync(stream.BeginRead, stream.EndRead,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; buffer, offset, count, null, TaskCreationOptions.DetachedFromParent);      &lt;br /&gt;}      &lt;br /&gt;      &lt;br /&gt;public static Task WriteTask(this Stream stream,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; byte [] buffer, int offset, int count)      &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; return Task.Factory.FromAsync(stream.BeginWrite, stream.EndWrite,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; buffer, offset, count, null, TaskCreationOptions.DetachedFromParent);      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;This then enables the previous code to be simplified to:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;static IEnumerable&amp;lt;Task&amp;gt; CopyStreamToStreamAsync(     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Stream input, Stream output)      &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; byte [] buffer = new byte[0x2000];      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; while(true)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; var read = input.ReadTask(buffer, 0, buffer.Length);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; yield return read;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (read.Result == 0) break;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; yield return output.WriteTask(buffer, 0, read.Result);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;That looks a lot like the synchronous version, and is *much* easier and less error-prone to write than the manual version shown earlier.&lt;/p&gt;  &lt;p&gt;Of course, now we need a mechanism for iterating over the asynchronous iterator. As mentioned, we can take advantage of ContinueWith for the main body of the operation (as with the earlier helpers, the following method and several variants of it are available in the &lt;a href="http://code.msdn.microsoft.com/ParExtSamples"&gt;Beta 1 samples&lt;/a&gt;):&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;public static Task Iterate(this TaskFactory factory,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; IEnumerable&amp;lt;Task&amp;gt; asyncIterator)      &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // Validate parameters      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; if (factory == null) throw new ArgumentNullException(&amp;quot;factory&amp;quot;);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; if (asyncIterator == null)       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; throw new ArgumentNullException(&amp;quot;asyncIterator&amp;quot;);      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // Get the scheduler to use, either the one provided by the factory      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // or the current one if the factory didn’t have one specified.      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; var scheduler = factory.TaskScheduler ?? TaskScheduler.Current;      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // Get an enumerator from the enumerable      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; var enumerator = asyncIterator.GetEnumerator();      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; if (enumerator == null) throw new InvalidOperationException();      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // Create the task to be returned to the caller. And ensure      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // that when everything is done, the enumerator is cleaned up.      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; var trs = new TaskCompletionSource&amp;lt;object&amp;gt;(factory.CreationOptions);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; trs.Task.ContinueWith(_ =&amp;gt; enumerator.Dispose(),       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; TaskContinuationOptions.DetachedFromParent, scheduler);      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // This will be called every time more work can be done.      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Action&amp;lt;Task&amp;gt; recursiveBody = null;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; recursiveBody = antecedent =&amp;gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; try      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // If the previous task completed with any exceptions, bail      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (antecedent != null &amp;amp;&amp;amp; antecedent.IsFaulted)       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; trs.TrySetException(antecedent.Exception);      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // If the user requested cancellation, bail.      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; else if (trs.Task.IsCancellationRequested) trs.TrySetCanceled();      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // If we should continue iterating and there's more to iterate      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // over, create a continuation to continue processing. We only      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // want to continue processing once the current Task (as yielded      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // from the enumerator) is complete.      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; else if (enumerator.MoveNext())      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; enumerator.Current.ContinueWith(recursiveBody,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; TaskContinuationOptions.DetachedFromParent, scheduler).      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IgnoreExceptions();      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // Otherwise, we're done!      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; else trs.TrySetResult(null);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // If MoveNext throws an exception, propagate that to the user      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; catch (Exception exc) { trs.TrySetException(exc); }      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; };      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // Get things started by launching the first task      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; factory.StartNew(() =&amp;gt; recursiveBody(null),       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; TaskCreationOptions.DetachedFromParent, scheduler).      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IgnoreExceptions();      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // Return the representative task to the user      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; return trs.Task;      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Using this implementation, we can now run “asynchronous methods” that return IEnumerable&amp;lt;Task&amp;gt;, as did our CopyStreamToStreamAsync method:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;var asyncOperation = Task.Factory.Iterate(     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; CopyStreamToStreamAsync(input, output));&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Note that the Iterate implementation shown includes a few handy additions on top of the previous hand-coded solution. First, the Iterate method returns a Task, which can be used to track the entire asynchronous operation. Second, it supports cancellation, meaning a caller can request that the asynchronous iteration to shutdown early, even if it hasn’t completed yet. Third, we’ve now separated out the run logic into a separate method, which means that we no longer need all of that goop in the actual target asynchronous method.&lt;/p&gt;  &lt;p&gt;On top of all that, this implementation is now based on TaskFactory, which means we can do things like ensure that the code runs on a certain scheduler, such as a scheduler that targets the UI. As an example of where that is handy, consider a method that asynchronously reads from a long, remote stream and stores the resulting data into a TextBox as it’s available:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;static IEnumerable&amp;lt;Task&amp;gt; ReadStreamIntoTextBox(Stream stream)     &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; byte [] buffer = new byte[0x2000];      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Encoding enc = new UTF8Encoder();      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; while(true)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; var read = stream.ReadTask(buffer, 0, buffer.Length);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; yield return read;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (read.Result == 0) break;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; myTextBox.Text += enc.GetString(buffer, 0, read.Result)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;As previously shown, I could invoke this method as follows:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;public void button1_Click(object sender, EventArgs e)     &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Task.Factory.Iterate(ReadStreamIntoTextBox(inputStream)); // buggy      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;However, accessing myTextBox.Text from a thread other than the thread that created myTextBox is a no-no, and yet that’s potentially what will happen in the above. To address that, I want to ensure that the actual code from the iterator is executed on the UI thread (but I still don’t want the asynchronous operations to block the UI thread). To accomplish that, I can create a TaskFactory that will run tasks on the UI thread, as I do in the following code:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;public void button1_Click(object sender, EventArgs e)     &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; var uiFactory = new TaskFactory(      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; TaskScheduler.FromCurrentSynchronizationContext());      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; uiFactory.Iterate(ReadStreamIntoTextBox(inputStream));      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Of course, while just being able to yield individual operations is useful, things get more interesting when you start considering multi-task continuations, as exposed through ContinueWhenAny and ContinueWhenAll. For example, in our previous copy stream example, we’re reading, then writing, then reading, then writing, and so forth. But we should be able to write the previously read bits while reading the next chunk, thereby achieving better speeds by overlapping latencies. Writing the code to do that using manual asynchrony would be a nightmare… with iterators and tasks, it’s manageable, almost fun:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;static IEnumerable&amp;lt;Task&amp;gt; CopyStreamToStreamAsync(     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Stream input, Stream output)      &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; byte[][] buffers = new byte[2][] {&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; new byte[BUFFER_SIZE], new byte[BUFFER_SIZE] };      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; int filledBufferNum = 0;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Task writeTask = null;      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; while (true)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; var readTask = input.ReadTask(      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; buffers[filledBufferNum], 0, buffers[filledBufferNum].Length);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; yield return writeTask == null ?      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; readTask :      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Task.Factory.ContinueWhenAll(new[] { readTask, writeTask },       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; tasks =&amp;gt; Task.WaitAll(tasks), // to propagate exceptions       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; TaskContinuationOptions.DetachedFromParent);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (readTask.Result == 0) break;      &lt;br /&gt;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; writeTask = output.WriteTask(      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; buffers[filledBufferNum], 0, readTask.Result);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; filledBufferNum = filledBufferNum == 0 ? 1 : 0;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Here, ContinueWhenAll is used to ensure that the iterator isn’t re-entered until both any pending writes and reads have completed.&lt;/p&gt;  &lt;p&gt;There are of course many variations to this code that you could implement. At the end of the day, I find it quite interesting to see how the Task primitive can be used to enable such scenarios.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9809774" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Code+Samples/default.aspx">Code Samples</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/.NET+4.0/default.aspx">.NET 4.0</category></item><item><title>Parallel For Loops over Non-Integral Types</title><link>http://blogs.msdn.com/pfxteam/archive/2009/06/24/9802037.aspx</link><pubDate>Wed, 24 Jun 2009 23:26:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9802037</guid><dc:creator>toub</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/9802037.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=9802037</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=9802037</wfw:comment><description>&lt;P&gt;In a previous post, it was demonstrated how for &lt;A href="http://blogs.msdn.com/pfxteam/archive/2009/06/06/9703059.aspx" mce_href="http://blogs.msdn.com/pfxteam/archive/2009/06/06/9703059.aspx"&gt;loops with very small loop bodies could be parallelized&lt;/A&gt; by creating an iterator over ranges, and then using Parallel.ForEach over those ranges.&amp;nbsp; A similar technique can be used to write parallel loops over iteration spaces of non-integers.&amp;nbsp; For example, let’s say I wanted to parallelize the following loop, where the iteration range is based on doubles:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;for(double d = 0.0; d &amp;lt; 1.0; d += .001) &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Process(d); &lt;BR&gt;}&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Parallel.For only contains overloads for where the iteration variable is an Int32 or an Int64.&amp;nbsp; To accomodate doubles, one approach would be to translate the range into an integer-based range in order to use Parallel.For, and then within the body of the loop translate it into a double.&amp;nbsp; As an example, the previously shown loop could be rewritten as:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;Parallel.For(0, 1000, i =&amp;gt; &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; double d = i / 1000.0; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Process(d); &lt;BR&gt;});&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Due to floating point arithmetic, this may not be exactly the same, but it may be close enough.&amp;nbsp; Another approach is to implement an iterator like the following:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;private static IEnumerable&amp;lt;double&amp;gt; Iterate( &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; double fromInclusive, double toExclusive, double step) &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; for(double d = fromInclusive; d &amp;lt; toExclusive; d += step) yield return d; &lt;BR&gt;}&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;With that Iterate method, now I can parallelize the sequential loop using Parallel.ForEach:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;Parallel.ForEach(Iterate(0.0, 1.0, .001), d =&amp;gt; &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Process(d); &lt;BR&gt;});&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;This same technique can be applied to a wide variety of scenarios.&amp;nbsp; Keep in mind, however, that the IEnumerator&amp;lt;T&amp;gt; interface isn’t thread-safe, which means that Parallel.ForEach needs to take locks when accessing the data source. While ForEach internally uses some smarts to try to ammortize the cost of such locks over the processing, this is still overhead that needs to be overcome by more work in the body of the ForEach in order for good speedups to be achieved.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Parallel.ForEach has optimizations used when working on indexible data sources, such as lists and arrays, and in those cases the need for locking is decreased.&amp;nbsp; Thus, performance may actually be improved in some cases by transforming the iteration space into a list or an array, which can be done using LINQ, even though there is both time and memory cost associated with creating an array from an enumerable. For example:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;Parallel.ForEach(Iterate(0.0, 1.0, .001).ToArray(), d =&amp;gt; &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Process(d); &lt;BR&gt;});&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Happy coding.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9802037" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Code+Samples/default.aspx">Code Samples</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/.NET+4.0/default.aspx">.NET 4.0</category></item><item><title>Cancellation in Parallel Extensions</title><link>http://blogs.msdn.com/pfxteam/archive/2009/06/22/9791840.aspx</link><pubDate>Mon, 22 Jun 2009 12:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9791840</guid><dc:creator>mikelid</dc:creator><slash:comments>8</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/9791840.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=9791840</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=9791840</wfw:comment><description>&lt;P&gt;One of the great features that crosses all of Parallel Extensions types is a consistent approach to cancellation (see &lt;A href="http://blogs.msdn.com/pfxteam/archive/2009/05/22/9635790.aspx" mce_href="http://blogs.msdn.com/pfxteam/archive/2009/05/22/9635790.aspx"&gt;http://blogs.msdn.com/pfxteam/archive/2009/05/22/9635790.aspx&lt;/A&gt;). In this post we explore some of the ways cancellation is used in Parallel Extensions and explain the guidance we developed. &lt;/P&gt;
&lt;P&gt;The new cancellation system is a cooperative approach based on two new types: CancellationTokenSource, which initiates cancellation requests, and CancellationToken which communicates a cancellation request to asynchronous operations and to long-running and blocking method calls.&lt;/P&gt;
&lt;P&gt;If you are experimenting with Parallel Extensions, you might like to keep an eye out for the methods that accept a CancellationToken and test them out. &lt;BR&gt;&lt;BR&gt;&lt;/P&gt;
&lt;H3&gt;Blocking calls&lt;/H3&gt;
&lt;P&gt;Some of the Parallel Extension types introduce blocking methods, for example BlockingCollection.Take() and Task.Wait(). The default overloads for these methods will block indefinitely if the condition they are waiting for never occurs. One solution used by these APIs, and many others like them, is to provide a timeout overload so that they may return after some duration and report that the condition did not occur. However, a timeout isn't particularly convenient if you only want to stop waiting if a specific activity occurs, such as a user clicking a 'cancel' button. One possibility is to wait for some amount of time such as 100 milliseconds, check if the button was pressed, and if not then go back to waiting, but this puts the burden on the call-site and must be re-implemented repeatedly; and depending on the frequency of the polling, it may also add unnecessary cost. The types in Parallel Extensions use the new cancellation system and provide overloads that accept a CancellationToken which can cause early termination of blocking methods in response to a specific cancellation request.&lt;/P&gt;
&lt;P&gt;Here are some examples of the blocking calls in Parallel Extensions that accept a CancellationToken:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;STRONG&gt;BlockingCollection: &lt;BR&gt;&lt;/STRONG&gt;void Add(T item, CancellationToken cancellationToken) &lt;BR&gt;T Take(CancellationToken cancellationToken)&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;STRONG&gt;ManualResetEventSlim: &lt;BR&gt;&lt;/STRONG&gt;void Wait(CancellationToken cancellationToken)&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;STRONG&gt;Task: &lt;BR&gt;&lt;/STRONG&gt;void Wait(CancellationToken cancellationToken) &lt;BR&gt;void WaitAll(Task[] tasks, CancellationToken cancellationToken)&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;In each case, you supply a CancellationToken to the method, and if the CancellationToken is signaled via a call to the associated CancellationTokenSource.Cancel(), then the method will wake up and throw an OperationCanceledException. This frees you from the need to use the timeouts if you are happy to wait until the condition is true or a specific cancellation request occurs. Many of these methods also have overloads that accept both a CancellationToken and a timeout, so that both needs may be accommodated. &lt;BR&gt;&lt;/P&gt;
&lt;H3&gt;Long-running calls&lt;/H3&gt;
&lt;P&gt;There are also a variety of methods that may simply take a while to complete, particularly if large amounts of data or complex processing is taking place. For example, the following call is likely to take some time, even if individual calls to DoFunc(x) are relatively fast:&lt;/P&gt;
&lt;P&gt;Parallel.For(1, 1000000000, (x) =&amp;gt; DoFunc(x));&lt;/P&gt;
&lt;P&gt;To assist with this, the Parallel APIs have overloads that accept a ParallelOptions class instance that holds a CancellationToken. The machinery inside Parallel.For(...)observes the supplied CancellationToken and will exit early if it sees that the token has be signaled (for more information on exiting loops early, see &lt;A href="http://blogs.msdn.com/pfxteam/archive/2009/05/27/9645023.aspx" mce_href="http://blogs.msdn.com/pfxteam/archive/2009/05/27/9645023.aspx"&gt;http://blogs.msdn.com/pfxteam/archive/2009/05/27/9645023.aspx&lt;/A&gt;). For example, &lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT size=2 face="Courier New"&gt;CancellationTokenSource cts = new CancellationTokenSource(); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;ParallelOptions options = new ParallelOptions &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {CancellationToken = cts.Token}; &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;Parallel.For(1, 100, options, (x) =&amp;gt; DoSlowFunc(x)); &lt;BR&gt;// from another thread, call cts.Cancel() to request cancellation.&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;As you can see, the approach for canceling blocking calls and long-running calls is identical. In both cases you supply a CancellationToken to a specific method call and use the associated CancellationTokenSource to signal a cancellation request. &lt;BR&gt;&lt;BR&gt;&lt;/P&gt;
&lt;H3&gt;Digression: Internal cancellation&lt;/H3&gt;
&lt;P&gt;In certain situations in Parallel Extensions and in other systems, it is necessary to wake up a blocked method for reasons that aren't due to explicit cancellation by a user. For example, if one thread is blocked on blockingCollection.Take() due to the collection being empty and another thread subsequently calls blockingCollection.CompleteAdding(), then the first call should wake up and throw an InvalidOperationException to represent an incorrect usage. A great way to implement this is to use an internal CancellationTokenSource that can wake things up due to internal concerns, and to link it to a second, external CancellationTokenSource that has been supplied by the user. For example, the following captures the essential details of how CompleteAdding() and Take(CancellationToken) are implemented:&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2 face="Courier New"&gt;class BlockingCollection&amp;lt;T&amp;gt; &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;{ &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp; CancellationTokenSource internalCTS = new CancellationTokenSource();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp; public void FinishAdding() &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //... &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; internalCTS.Cancel(); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp; }&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;public T Take(CancellationToken externalToken) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; using(CancellationTokenSource linkedTokenSource = &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; CancellationTokenSource.CreateLinkedTokenSource( &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; internalCTS.Token, externalToken)){ &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; try &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return InternalTake(linkedTokenSource.Token); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; catch (OperationCanceledException oce) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(internalCTS.Token.IsCancellationRequested) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new InvalidOperationException("..msg.."); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else if(externalToken.IsCancellationRequested) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new OperationCanceledException(externalToken); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else throw; &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;} &lt;BR&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;In this fragment, a linked CancellationTokenSource is created and its token passed to the InternalTake() method. This simplifies the implementation for InternalTake() but still allows it to be woken up due to either the external token being signaled or an incorrect concurrent call to CompleteAdding(). If the InternalTake() method throws an OperationCanceledException, we can test the individual tokens to determine what the cause was and take appropriate action. Note that oce.CancellationToken will be equal to linkedTokenSource.Token as this is the token that was actually being observed, but we can look at the original tokens to determine the cause for the linked token being signaled. There is a minor risk of confusion if both sources are signaled simultaneously, but this confusion is benign as it is reasonable to behave as though either source was responsible, and a particular implementation may choose to prioritize one mechanism over the other. &lt;BR&gt;&lt;/P&gt;
&lt;H3&gt;Cooperative cancellation with user-code&lt;/H3&gt;
&lt;P&gt;Both TPL and PLINQ provide infrastructure that calls back to user code. If the user code is long running or blocking, then it is very useful for the user code to be able to respond to cancellation in a cooperative fashion. TPL and PLINQ achieve this by tracking a supplied CancellationToken, and if they see some user code throw an OperationCanceledException that mentions this specific token, then it is treated as &lt;I&gt;cooperative acknowledgement of cancellation&lt;/I&gt;. This means that both TPL and PLINQ understand that the user code did not suffer some catastrophic exceptional conditional, but rather that it is simply responding to cancellation. As a result, TPL and PLINQ constructs will simply exit with an OperationCanceledException of their own, rather than aggregating exceptions from all the participating worker threads and throwing an AggregateException.&lt;/P&gt;
&lt;P&gt;PLINQ follows this basic plan; for example, the following query will throw a single OperationCanceledException if the CancellationTokenSource becomes signaled. It doesn't matter whether PLINQ or the user delegate sees the cancellation request first, as the user-delegate exception will be correctly understood by the PLINQ execution engine.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT size=2 face="Courier New"&gt;CancellationTokenSource cts = new CancellationTokenSource(); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;var resultArray = &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;data.AsParallel() &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .WithCancellation(cts.Token) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .Select((x) =&amp;gt; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (cts.Token.IsCancellationRequested) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new OperationCanceledException(cts.Token); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // ... &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .ToArray();&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;In both PLINQ and TPL, it is interesting to note that the external cancellation token is not supplied back to the user-delegate via a parameter as may be expected. This would have bloated the number of method overloads considerably and, as shown above, the external token can be conveniently accessed via closures or equivalent techniques.&lt;/P&gt;
&lt;P&gt;If the user code throws an OperationCanceledException but one or more "normal" exceptions occur on other threads, then all of the exceptions will be collated into an AggregateException, including the OperationCanceledException. Hence, if only cancellation occurred then a single OperationCanceledException is thrown, but an actual failure will always result in an AggregateException. &lt;BR&gt;&lt;BR&gt;&lt;/P&gt;
&lt;H3&gt;PLINQ Queries&lt;/H3&gt;
&lt;P&gt;PLINQ offers deep support for cancellation and endeavors to ensure that cancellation will be enacted swiftly for any query. For queries that involve only simple and fast user delegates, simply supply a CancellationToken via the WithCancellation() method and PLINQ takes care of the rest. &lt;A&gt;&lt;FONT color=#000000&gt;If your query involves long-running or blocking user code, then you should use the cooperative cancellation pattern described in the preceding section&lt;/FONT&gt;&lt;/A&gt;. For reasons that are discussed in the next section, PLINQ may not check for cancellation every time it calls a user-delegate, and so long running delegates should check cancellation frequently (&lt;A&gt;&lt;FONT color=#000000&gt;as a working rule of thumb, PLINQ will check for cancellation approximately once per one hundred calls to a user delegate&lt;/FONT&gt;&lt;/A&gt;). For example, if a delegate call runs for 50ms but does not perform any cancellation checks of its own, then PLINQ may not detect the cancellation request itself for up to 5 seconds, and this could significantly affect a user’s experience. For this reason, we recommend that long-running delegates called from PLINQ queries should check for cancellation as frequently as possible. A good lower bound is to check cancellation once per few thousand IL instructions executed, and an upper bound is to check no less frequently than once per 10ms, but once per 1ms is preferred to ensure snappy response.&lt;/P&gt;
&lt;P&gt;The following example demonstrates a user delegate that may run for a while, and so checks cancellation itself every few thousand IL instructions. This provides for timely cancellation support with a negligible cost to performance.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT size=2 face="Courier New"&gt;// Assume an external CancellationToken 'token' has been supplied. &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;int[] data = ...; &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;var query = &lt;BR&gt;&amp;nbsp;&amp;nbsp; data.AsParallel() &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .WithCancellation(token) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .Select((x) =&amp;gt; &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int result = 0; &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for ( int i = 0; i &amp;lt; x; i++ ) { &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for (int j = 0; j &amp;lt; 1000 * x; j++) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; result += SimpleFunc(i,j); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; token.ThrowIfCancellationRequested(); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return result;}) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .ToArray();&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;[Update: the call to token.ThrowIfCancellationRequested shown above is not available in Beta1 (but will appear in subsequent releases).&amp;nbsp; This behavior can be acheived via a manual test-and-throw as shown in earlier examples, or via the extension-method approach described in the comments.&amp;nbsp; -Mike]&lt;/P&gt;
&lt;H3&gt;Summary&lt;/H3&gt;
&lt;P&gt;The Parallel Extension types use the new cancellation system to provide consistent and rich cancellation features. All of the long-running and blocking methods in Parallel Extensions provide overloads that take a CancellationToken, and any callbacks made to user-code can participate in the process. Application code can also make use of the same ideas and facilities to ensure that cancellation can be a fully supported feature in any situation.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9791840" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/PLINQ/default.aspx">PLINQ</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Code+Samples/default.aspx">Code Samples</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Coordination+Data+Structures/default.aspx">Coordination Data Structures</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/CDS/default.aspx">CDS</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/.NET+4.0/default.aspx">.NET 4.0</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Cancellation/default.aspx">Cancellation</category></item><item><title>Tasks and the Event-based Asynchronous Pattern</title><link>http://blogs.msdn.com/pfxteam/archive/2009/06/19/9791857.aspx</link><pubDate>Fri, 19 Jun 2009 18:43:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9791857</guid><dc:creator>toub</dc:creator><slash:comments>13</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/9791857.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=9791857</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=9791857</wfw:comment><description>&lt;P&gt;As has been discussed previously, one of the new features in the Task Parallel Library is &lt;A href="http://blogs.msdn.com/pfxteam/archive/2009/06/02/9685804.aspx" mce_href="http://blogs.msdn.com/pfxteam/archive/2009/06/02/9685804.aspx"&gt;TaskCompletionSource&amp;lt;TResult&amp;gt;&lt;/A&gt;, which enables the creation of a Task&amp;lt;TResult&amp;gt; that represents any other asynchronous operation.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;There are a wide variety of sources in the .NET Framework for asynchronous work.&amp;nbsp; One comes from components that implement the Asynchronous Programming Model (APM) pattern, which we discussed &lt;A href="http://blogs.msdn.com/pfxteam/archive/2009/06/09/9716439.aspx" mce_href="http://blogs.msdn.com/pfxteam/archive/2009/06/09/9716439.aspx"&gt;here&lt;/A&gt;.&amp;nbsp; Another includes types that implement the Event-based Asynchronous Pattern (EAP).&amp;nbsp; For some synchronous method Xyz, the EAP provides an asynchronous counterpart XyzAsync.&amp;nbsp; Calling this method launches the asynchronous work, and when the work completes, a corresponding XyzCompleted event is raised. (That’s an oversimplification of the pattern, but it provides a grounding.)&lt;/P&gt;
&lt;P&gt;For many situations, the EAP is quite straightforward and simple to use.&amp;nbsp; However, there are cases where you’d like to be able to do things like join across multiple EAP asynchronous invocations, such as to download three different web pages asynchronously, and only when all three have completed do something else.&amp;nbsp; Tasks in .NET 4.0 make this kind of operation easy, through Task.Factory.ContinueWhenAll (or ContinueWhenAny if you want to do something when any one of the items completes rather than when all of them do).&amp;nbsp; However, in order to use these methods, you need Tasks, thus to use them with components that implement the EAP, you need to create Tasks from EAP.&amp;nbsp; TaskCompletionSource&amp;lt;TResult&amp;gt; can be used to do exactly that. &lt;/P&gt;
&lt;P&gt;First, let’s create two small helper functions that we can reuse over and over for multiple EAP-to-Task implementations: &lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;private static TaskCompletionSource&amp;lt;T&amp;gt; CreateSource&amp;lt;T&amp;gt;(object state) &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return new TaskCompletionSource&amp;lt;T&amp;gt;( &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; state, TaskCreationOptions.DetachedFromParent); &lt;BR&gt;} &lt;/P&gt;
&lt;P&gt;private static void TransferCompletion&amp;lt;T&amp;gt;( &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; TaskCompletionSource&amp;lt;T&amp;gt; tcs, AsyncCompletedEventArgs e, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Func&amp;lt;T&amp;gt; getResult, Action unregisterHandler) &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (e.UserState == tcs) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (e.Cancelled) tcs.TrySetCanceled(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else if (e.Error != null) tcs.TrySetException(e.Error); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else tcs.TrySetResult(getResult()); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (unregisterHandler != null) unregisterHandler();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;}&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;The first helper, CreateSource, simply creates an instance of TaskCompletionSource&amp;lt;T&amp;gt; with the right type and settings.&amp;nbsp; I’ve included TaskCreationOptions.DetachedFromParent under the assumption that tasks created for the EAP pattern aren’t necessarily meant to participate in parent/child relationships, but you could certainly change this if your scenarios needed that functionality. &lt;/P&gt;
&lt;P&gt;The second helper, TransferCompletion, will be used whenever an EAP event signals completion of an asynchronous operation.&amp;nbsp; It takes the AsyncCompletedEventArgs provided through the XyzCompleted event and uses it to determine whether the operation completed due to cancellation or due to an unhandled exception.&amp;nbsp; Both of those pieces of data are standard to the base AsyncCompletedEventArgs class. However, each EAP operation typically comes with its own type derived from AsyncCompletedEventArgs: to be able to use this one helper function with any of those to mine the result of the operation, TransferCompletion also accepts a Func&amp;lt;T&amp;gt; that will return the results from the derived instance.&lt;/P&gt;
&lt;P&gt;With those two helpers, writing a Task wrapper for an EAP operation is a cinch.&amp;nbsp; Consider System.Net.WebClient, which provides support for downloading and uploading to and from URIs, with methods like DownloadData.&amp;nbsp; We can write a Task-based wrapper for DownloadData in just a few lines (in this case, as an extension method): &lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;public static Task&amp;lt;byte[]&amp;gt; DownloadDataTask( &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; this WebClient webClient, Uri address) &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var tcs = CreateSource&amp;lt;byte[]&amp;gt;(address); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; webClient.DownloadDataCompleted += &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (sender, e) =&amp;gt; TransferCompletion(tcs, e, () =&amp;gt; e.Result, null); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; webClient.DownloadDataAsync(address, tcs); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return tcs.Task; &lt;BR&gt;}&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;We first create a TaskCompletionSource&amp;lt;byte[]&amp;gt; whose Task&amp;lt;byte[]&amp;gt; will be returned from the method.&amp;nbsp; We then register with the DownloadDataCompleted event handler, such that when the event is raised, the downloaded data (or exception or cancellation information) will be transferred to the returned Task.&amp;nbsp; And then we start the operation.&amp;nbsp; Piece of cake. &lt;/P&gt;
&lt;P&gt;One interesting thing to note about the EAP is that some implementations support multiple asynchronous operations concurrently on the same instance.&amp;nbsp; In such cases, a user-supplied token is needed to correlate the asynchronous invocations to the asynchronous completions (something that’s provided in Task implicitly by having a Task reference returned from and serving as a reference for an asynchronous operation).&amp;nbsp; For that purpose, we pass the created TaskCompletionSource&amp;lt;TResult&amp;gt; as the user-supplied token, and in TransferCompletion, we only transfer the results if the token received matches the target completion source.&amp;nbsp; If it doesn’t match, this is an event completion for another operation and should be ignored. &lt;/P&gt;
&lt;P&gt;One potential issue with the previously shown implementation (and with the EAP pattern in general) is that, if they’re used over and over, the XyzCompleted event handlers will start to build up.&amp;nbsp; Delegates are being registered with the event but not released.&amp;nbsp; To fix that, we can also remove the event handler in the delegate handling the event.&amp;nbsp; For example, DownloadDataTask can be rewritten as: &lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;public static Task&amp;lt;byte[]&amp;gt; DownloadDataTask( &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; this WebClient webClient, Uri address) &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var tcs = CreateSource&amp;lt;byte[]&amp;gt;(address); &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; DownloadDataCompletedEventHandler handler = null; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; handler = (sender, e) =&amp;gt; TransferCompletionToTask(tcs, e, () =&amp;gt; e.Result, () =&amp;gt; webClient.DownloadDataCompleted -= handler);&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; webClient.DownloadDataCompleted += handler; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; try { webClient.DownloadDataAsync(address, tcs); } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; catch { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; webClient.DownloadDataCompleted -= handler; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; tcs.TrySetCanceled(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return tcs.Task; &lt;BR&gt;}&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;The Beta 1 samples available at &lt;A title=http://code.msdn.microsoft.com/ParExtSamples href="http://code.msdn.microsoft.com/ParExtSamples" mce_href="http://code.msdn.microsoft.com/ParExtSamples"&gt;http://code.msdn.microsoft.com/ParExtSamples&lt;/A&gt; already include Task-based extensions for WebClient, as well as extensions for other EAP implementations like SmtpClient and Ping.&amp;nbsp; Download and enjoy!&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9791857" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/.NET+4.0/default.aspx">.NET 4.0</category></item><item><title>How PLINQ processes an IEnumerable&lt;T&gt; on multiple cores</title><link>http://blogs.msdn.com/pfxteam/archive/2009/06/13/9741072.aspx</link><pubDate>Sat, 13 Jun 2009 12:39:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9741072</guid><dc:creator>igoro</dc:creator><slash:comments>15</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/9741072.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=9741072</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=9741072</wfw:comment><description>&lt;P&gt;As Ed Essey explained in &lt;A title="Partitioning in PLINQ" href="http://blogs.msdn.com/pfxteam/archive/2009/05/28/9648672.aspx" mce_href="http://blogs.msdn.com/pfxteam/archive/2009/05/28/9648672.aspx"&gt;Partitioning in PLINQ&lt;/A&gt;, partitioning is an important step in PLINQ execution. Partitioning splits up a single input sequence into multiple sequences that can be processed in parallel. This post further explains chunk partitioning, the most general partitioning scheme that works on any IEnumerable&amp;lt;T&amp;gt;.&lt;/P&gt;
&lt;P&gt;Chunk partitioning appears in two places in Parallel Extensions. First, it is one of the algorithms that PLINQ uses under the hood to execute queries in parallel. Second, chunk partitioning is available as a standalone algorithm through the Partitioner.Create() method.&lt;/P&gt;
&lt;P&gt;To explain the design of the chunk partitioning algorithm, let's walk through the possible ways of processing an IEnumerable&amp;lt;T&amp;gt; with multiple worker threads, finally arriving at the solution used in PLINQ (approach 4).&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&lt;STRONG&gt;Approach 1: Load the input sequence into an intermediate array&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;As a simple solution, we could walk over the input sequence and store all elements into an array. Then, we can split up the array into ranges, and assign each range to a different worker.&lt;/P&gt;
&lt;P&gt;The disadvantage of this approach is that we need to allocate an array large enough to store all input elements. If the input sequence is long, this will algorithm leads to unnecessarily large memory consumption. Also, we need to wait until the entire input sequence is ready before the workers can start executing.&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&lt;STRONG&gt;Approach 2: Hand out elements to threads on demand&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;An entirely different approach is to have all worker threads share one input enumerator. When a worker is ready to process the next input element, it takes a shared lock, gets the next element from the input enumerator, and releases the lock.&lt;/P&gt;
&lt;P&gt;This algorithm has a fairly large overhead because processing every element requires locking. Also, handing out elements individually is prone to poor cache behavior.&lt;/P&gt;
&lt;P&gt;This approach does have an interesting advantage over Approach 1, though: since workers receive data on demand, the workers that finish faster will come back to request more work. In contrast, Approach 1 splits up all work ahead of time, and a worker that is done early simply goes away.&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&lt;STRONG&gt;Approach 3: Hand out elements in chunks&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;To mitigate the two drawbacks of Approach 2 (synchronization cost and cache behavior), we can hand out elements to threads in "chunks". When a thread is ready to process more inputs, it will take say 64 elements from the input enumerator.&lt;/P&gt;
&lt;P&gt;Unfortunately, while this approach nicely amortizes the synchronization cost over multiple elements, it does not work well for short inputs. For example, if the input contains 50 elements and the chunk size is 64, all inputs will go into a single partition. Even if the work per element is large, we will not be able to benefit from parallelism, since one worker gets all the work.&lt;/P&gt;
&lt;P&gt;And since IEnumerable&amp;lt;T&amp;gt; in general does not declare its length, we cannot simply tune the chunk size based on the input sequence length.&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&lt;STRONG&gt;Approach 4: Hand out elements in chunks of increasing size&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;A solution to the problem with small inputs is to use chunks of a growing size. The first chunk assigned to each thread is of size 1 and subsequent chunks are gradually larger, until a specific threshold is reached.&lt;/P&gt;
&lt;P&gt;Our solution doubles the chunk size every few chunks. So, each thread first receives a few chunks of size 1, then a few chunks of size 2, then 4, and so forth. Once the chunk size reaches a certain threshold, it remains constant.&lt;/P&gt;
&lt;P&gt;This chunking strategy ensures that if the input is short, it will still get split up fairly among the cores. But, the chunk size also grows fairly quickly, and the per-chunk overheads are small for large inputs. Also, the algorithm is quite good at load-balancing, so if one worker is taking longer to process its inputs, other workers will process more elements to decrease the overall processing time.&lt;/P&gt;
&lt;P&gt;One interesting consequence of the chunk partitioning algorithm is that multiple threads will call MoveNext() on the input enumerator. The worker threads will use a lock to ensure mutual exclusion, but the enumerator must not assume that MoveNext() will be called from a particular thread (e.g., it should not use thread-local storage, manipulate UI, etc).&lt;/P&gt;
&lt;P&gt;The current implementation of both PLINQ chunk partitioning and Partitioner.Create() follows approach 4 fairly closely. Now you know&amp;nbsp;how it behaves&amp;nbsp;and why!&lt;BR&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9741072" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/PLINQ/default.aspx">PLINQ</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/.NET+4.0/default.aspx">.NET 4.0</category></item></channel></rss>