{"id":56042,"date":"2011-10-24T13:33:11","date_gmt":"2011-10-24T13:33:11","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/pfxteam\/2011\/10\/24\/task-run-vs-task-factory-startnew\/"},"modified":"2011-10-24T13:33:11","modified_gmt":"2011-10-24T13:33:11","slug":"task-run-vs-task-factory-startnew","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/task-run-vs-task-factory-startnew\/","title":{"rendered":"Task.Run vs Task.Factory.StartNew"},"content":{"rendered":"<p>In .NET 4, Task.Factory.StartNew was the primary method for scheduling a new task.&nbsp; Many overloads provided for a highly configurable mechanism, enabling setting options, passing in arbitrary state, enabling cancellation, and even controlling scheduling behaviors.&nbsp; The flip side of all of this power is complexity.&nbsp; You need to know when to use which overload, what scheduler to provide, and the like. And &ldquo;Task.Factory.StartNew&rdquo; doesn&rsquo;t exactly roll off the tongue, at least not quickly enough for something that&rsquo;s used in such primary scenarios as easily offloading work to background processing threads.<\/p>\n<p>So, in the .NET Framework 4.5 Developer Preview, we&rsquo;ve introduced the new Task.Run method.&nbsp; This in no way obsoletes Task.Factory.StartNew, but rather should simply be thought of as a quick way to use Task.Factory.StartNew without needing to specify a bunch of parameters.&nbsp; It&rsquo;s a shortcut.&nbsp; In fact, Task.Run is actually implemented in terms of the same logic used for Task.Factory.StartNew, just passing in some default parameters.&nbsp; When you pass an Action to Task.Run:<\/p>\n<blockquote>\n<p><font face=\"Consolas\">Task.Run(someAction);<\/font><\/p>\n<\/blockquote>\n<p>that&rsquo;s exactly equivalent to:<\/p>\n<blockquote>\n<p><font face=\"Consolas\">Task.Factory.StartNew(someAction,        <br>&nbsp;&nbsp;&nbsp; CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);<\/font><\/p>\n<\/blockquote>\n<p>In this way, Task.Run can and should be used for the most common cases of simply offloading some work to be processed on the ThreadPool (what TaskScheduler.Default targets).&nbsp; That doesn&rsquo;t mean Task.Factory.StartNew will never again be used; far from it.&nbsp; Task.Factory.StartNew still has many important (albeit more advanced) uses.&nbsp; You get to control TaskCreationOptions for how the task behaves.&nbsp; You get to control the scheduler for where the task should be queued to and run.&nbsp; You get to use overloads that accept object state, which for performance-sensitive code paths can be used to avoid closures and the corresponding allocations.&nbsp; For the simple cases, though, Task.Run is your friend.<\/p>\n<p>Task.Run provides eight overloads, to support all combinations of the following:<\/p>\n<ol>\n<li>Task vs Task&lt;TResult&gt; <\/li>\n<li>Cancelable vs non-cancelable <\/li>\n<li>Synchronous vs asynchronous delegate <\/li>\n<\/ol>\n<p>The first two bullets should be self-explanatory.&nbsp; For the first bullet, there are overloads that return Task (for operations that don&rsquo;t have a result) and there are overloads that return Task&lt;TResult&gt; (for operations that have a result of type TResult).&nbsp; There are also overloads that accept a CancellationToken, which enables the Task Parallel Library (TPL) to transition the task to a Canceled state if cancellation is requested prior to the task beginning its execution.<\/p>\n<p>The third bullet is more interesting, and is directly related to the async language support in C# and Visual Basic in Visual Studio 11.&nbsp; Let&rsquo;s consider Task.Factory.StartNew for a moment, as that will help to highlight what this distinction is.&nbsp; If I write the following call:<\/p>\n<blockquote>\n<p><font face=\"Consolas\">var t = Task.Factory.StartNew(() =&gt;        <br>{         <br>&nbsp;&nbsp;&nbsp; Task inner =Task.Factory.StartNew(() =&gt; {});         <br>&nbsp;&nbsp;&nbsp; return inner;         <br>});<\/font><\/p>\n<\/blockquote>\n<p>the type of &lsquo;t&rsquo; is going to be Task&lt;Task&gt;; the task&rsquo;s delegate is of type Func&lt;TResult&gt;, TResult in this case is a Task, and thus StartNew is returning a Task&lt;Task&gt;.&nbsp; Similarly, if I were to change that to be:<\/p>\n<blockquote>\n<p><font face=\"Consolas\">var t = Task.Factory.StartNew(() =&gt;        <br>{         <br>&nbsp;&nbsp;&nbsp; Task&lt;int&gt; inner = Task.Factory.StartNew(() =&gt; 42));         <br>&nbsp;&nbsp;&nbsp; return inner;         <br>});<\/font><\/p>\n<\/blockquote>\n<p>the type of &lsquo;t&rsquo; is now going to be Task&lt;Task&lt;int&gt;&gt;.&nbsp; The task&rsquo;s delegate is Func&lt;TResult&gt;, TResult is now Task&lt;int&gt;, and thus StartNew is returning Task&lt;Task&lt;int&gt;&gt;.&nbsp; Why is this relevant?&nbsp; Consider now what happens if I write the following:<\/p>\n<blockquote>\n<p><font face=\"Consolas\">var t = Task.Factory.StartNew(async delegate        <br>{         <br>&nbsp;&nbsp;&nbsp; await Task.Delay(1000);         <br>&nbsp;&nbsp;&nbsp; return 42;         <br>});<\/font><\/p>\n<\/blockquote>\n<p>By using the async keyword here, the compiler is going to map this delegate to be a Func&lt;Task&lt;int&gt;&gt;: invoking the delegate will return the Task&lt;int&gt; to represent the eventual completion of this call.&nbsp; And since the delegate is Func&lt;Task&lt;int&gt;&gt;, TResult is Task&lt;int&gt;, and thus the type of &lsquo;t&rsquo; is going to be Task&lt;Task&lt;int&gt;&gt;, not Task&lt;int&gt;.<\/p>\n<p>To handle these kinds of cases, in .NET 4 we introduced the Unwrap method.&nbsp; Unwrap has two overloads, which are both extensions methods, one on type Task&lt;Task&gt; and one on type Task&lt;Task&lt;TResult&gt;&gt;.&nbsp; We called this method Unwrap because it, in effect, &ldquo;unwraps&rdquo; the inner task that&rsquo;s returned as the result of the outer task.&nbsp; Calling Unwrap on a Task&lt;Task&gt; gives you back a new Task (which we often refer to as a proxy) which represents the eventual completion of the inner task.&nbsp; Similarly, calling Unwrap on a Task&lt;Task&lt;TResult&gt;&gt; gives you back a new Task&lt;TResult&gt; which represents the eventual completion of that inner task. (In both cases, if the outer task is Faulted or Canceled, there is no inner task, since there&rsquo;s no result from a task that doesn&rsquo;t run to completion, so the proxy task then represents the state of the outer task.) Going back to the prior example, if I wanted &lsquo;t&rsquo; to represent the return value of that inner task (in this case, the value 42), I could write:<\/p>\n<blockquote>\n<p><font face=\"Consolas\">var t = Task.Factory.StartNew(async delegate        <br>{         <br>&nbsp;&nbsp;&nbsp; await Task.Delay(1000);         <br>&nbsp;&nbsp;&nbsp; return 42;         <br>})<strong>.Unwrap();<\/strong><\/font><\/p>\n<\/blockquote>\n<p>The &lsquo;t&rsquo; variable will now be of type Task&lt;int&gt;, representing the result of that asynchronous invocation.<\/p>\n<p>Enter Task.Run.&nbsp; Because we expect it to be so common for folks to want to offload work to the ThreadPool, and for that work to use async\/await, we decided to build this unwrapping functionality into Task.Run.&nbsp; That&rsquo;s what&rsquo;s referred to by the third bullet above.&nbsp; There are overloads of Task.Run that accept Action (for void-returning work), Func&lt;TResult&gt; (for TResult-returning work), Func&lt;Task&gt; (for void-returning async work), and Func&lt;Task&lt;TResult&gt;&gt; (for TResult-returning async work).&nbsp; Internally, then, Task.Run does the same kind of unwrapping that&rsquo;s shown with Task.Factory.StartNew above.&nbsp; So, when I write:<\/p>\n<blockquote>\n<p><font face=\"Consolas\">var t = Task.Run(async delegate        <br>{         <br>&nbsp;&nbsp;&nbsp; await Task.Delay(1000);         <br>&nbsp;&nbsp;&nbsp; return 42;         <br>});<\/font><\/p>\n<\/blockquote>\n<p>the type of &lsquo;t&rsquo; is Task&lt;int&gt;, and the implementation of this overload of Task.Run is basically equivalent to:<\/p>\n<blockquote>\n<p><font face=\"Consolas\">var t = Task.Factory.StartNew(async delegate        <br>{         <br>&nbsp;&nbsp;&nbsp; await Task.Delay(1000);&nbsp; <br>&nbsp;&nbsp;&nbsp; return 42;         <br>}, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default).Unwrap();<\/font><\/p>\n<\/blockquote>\n<p>As mentioned before, it&rsquo;s a shortcut.<\/p>\n<p>All of this then means that you can use Task.Run either with either regular lambdas\/anonymous methods or with async lambdas\/anonymous methods, and the right thing will just happen.&nbsp; If I wanted to offload this work to the ThreadPool and await its result, e.g.<\/p>\n<blockquote>\n<p><font face=\"Consolas\">int result = await Task.Run(async () =&gt;        <br>{         <br>&nbsp;&nbsp;&nbsp; await Task.Delay(1000);         <br>&nbsp;&nbsp;&nbsp; return 42;         <br>});<\/font><\/p>\n<\/blockquote>\n<p>the type of <em>result<\/em> will be int, just as you&rsquo;d expect, and approximately one second after this work is invoked, the <em>result<\/em> variable be set to the value 42.<\/p>\n<p>Interestingly, the new await keyword can almost be thought of as a language equivalent to the Unwrap method.&nbsp; So, if we return back to our Task.Factory.StartNew example, I could rewrite the last snippet above as follows using Unwrap:<\/p>\n<blockquote>\n<p><font face=\"Consolas\">int result = await Task.Factory.StartNew(async delegate        <br>{         <br>&nbsp;&nbsp;&nbsp; await Task.Delay(1000);         <br>&nbsp;&nbsp;&nbsp; return 42;         <br>}, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default).Unwrap();<\/font><\/p>\n<\/blockquote>\n<p>or, instead of using Unwrap, I could use a second await:<\/p>\n<blockquote>\n<p><font face=\"Consolas\">int result = <strong>await<\/strong> await Task.Factory.StartNew(async delegate         <br>{         <br>&nbsp;&nbsp;&nbsp; await Task.Delay(1000);         <br>&nbsp;&nbsp;&nbsp; return 42;         <br>}, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);<\/font><\/p>\n<\/blockquote>\n<p>&ldquo;await await&rdquo; here is not a typo.&nbsp; Task.Factory.StartNew is returning a Task&lt;Task&lt;int&gt;&gt;.&nbsp; Await&rsquo;ing that Task&lt;Task&lt;int&gt;&gt; returns a Task&lt;int&gt;, and awaiting that Task&lt;int&gt; returns an int.&nbsp; Fun, right?<\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In .NET 4, Task.Factory.StartNew was the primary method for scheduling a new task.&nbsp; Many overloads provided for a highly configurable mechanism, enabling setting options, passing in arbitrary state, enabling cancellation, and even controlling scheduling behaviors.&nbsp; The flip side of all of this power is complexity.&nbsp; You need to know when to use which overload, what [&hellip;]<\/p>\n","protected":false},"author":360,"featured_media":58792,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[7908],"tags":[7907,7925,7909,7912],"class_list":["post-56042","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-pfxteam","tag-net-4","tag-net-4-5","tag-parallel-extensions","tag-task-parallel-library"],"acf":[],"blog_post_summary":"<p>In .NET 4, Task.Factory.StartNew was the primary method for scheduling a new task.&nbsp; Many overloads provided for a highly configurable mechanism, enabling setting options, passing in arbitrary state, enabling cancellation, and even controlling scheduling behaviors.&nbsp; The flip side of all of this power is complexity.&nbsp; You need to know when to use which overload, what [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/56042","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/360"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=56042"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/56042\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58792"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=56042"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=56042"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=56042"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}