首页 > 其他分享 >Task.Run vs Task.Factory.StartNew

Task.Run vs Task.Factory.StartNew

时间:2022-12-26 16:46:24浏览次数:49  
标签:Task Run StartNew await Factory task vs

Task.Factory.StartNew 内部开启子线程后的调度等待慢的问题。将同步阻塞改为不依赖环境上下文的方式:
async/await 

Interestingly, the new await keyword can almost be thought of as a language equivalent to the Unwrap method.  So, if we return back to our Task.Factory.StartNew example, I could rewrite the last snippet above as follows using Unwrap:

int result = await Task.Factory.StartNew(async delegate
{
    await Task.Delay(1000);
    return 42;
}, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default).Unwrap();

  

or, instead of using Unwrap, I could use a second await:

int result = await await Task.Factory.StartNew(async delegate
{
    await Task.Delay(1000);
    return 42;
}, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);

  

“await await” here is not a typo.  Task.Factory.StartNew is returning a Task<Task<int>>.  Await’ing that Task<Task<int>> returns a Task<int>, and awaiting that Task<int> returns an int.  Fun, right?

 

 

 

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Threading;
 5 using System.Threading.Tasks;
 6 using System.Diagnostics;
 7 using System.Net.Http;
 8 
 9 
10 static class Program
11     {
12 
13         /// <summary>
14         /// 应用程序的主入口点。
15         /// </summary>
16         [STAThread]
17         static   void Main(string[] args)
18         {
19 
20             var httpClient = new HttpClient();
21 
22             var url ="https://www.taoabo.cn/download/d6e5d8f2e47f46349c5f566cf5127e7658274de4.json";
23 
24 
25             Console.WriteLine($"0000000000000000000000");
26             var message2 = new HttpRequestMessage(HttpMethod.Get, url);
27             var sw2 = new Stopwatch();
28             sw2.Start();
29             var res2 = httpClient.SendAsync(message2).Result.Content.ReadAsByteArrayAsync().Result;
30             sw2.Stop();
31             Console.WriteLine($"currentThread:{Thread.CurrentThread.ManagedThreadId.ToString()},useTime:{sw2.ElapsedMilliseconds}");
32             Console.WriteLine($"1111111111111111111");
33 
34 
35 
36 
37             var arrTsks = new Task[10];
38             for (int i = 0; i < 10; i++)
39             {
40                var t=   Task.Factory.StartNew( async () =>
41                 {
42                     Console.WriteLine($"111:{Thread.CurrentThread.ManagedThreadId.ToString()}");
43                     var message = new HttpRequestMessage(HttpMethod.Get, url);
44                     var sw = new Stopwatch();
45                     sw.Start();
46 
47                     var res = await httpClient.SendAsync(message);//.Result.Content.ReadAsByteArrayAsync().Result;
48                     var raa = await res.Content.ReadAsStringAsync();
49 
50                     Console.WriteLine($"www:{Thread.CurrentThread.ManagedThreadId.ToString()}");
51 
52                     sw.Stop();
53                     Console.WriteLine($":{Thread.CurrentThread.ManagedThreadId.ToString()},currentThread:{Thread.CurrentThread.ManagedThreadId.ToString()},useTime:{sw.ElapsedMilliseconds}");
54                     Console.WriteLine($"qqq:{Thread.CurrentThread.ManagedThreadId.ToString()}");
55                 },CancellationToken.None);
56 
57                 arrTsks[i] = t;
58 
59             }
60 
61             Task.WaitAll(arrTsks);
62             //Thread.Sleep(1000000);
63 
64             Console.ReadKey();
65             int x = 0;
66 
67         }
68 
69 
70 
71     }

 

 

Task.Run vs Task.Factory.StartNew

Stephen Toub - MSFT

 

October 24th, 20110 0

In .NET 4, Task.Factory.StartNew was the primary method for scheduling a new task.  Many overloads provided for a highly configurable mechanism, enabling setting options, passing in arbitrary state, enabling cancellation, and even controlling scheduling behaviors.  The flip side of all of this power is complexity.  You need to know when to use which overload, what scheduler to provide, and the like. And “Task.Factory.StartNew” doesn’t exactly roll off the tongue, at least not quickly enough for something that’s used in such primary scenarios as easily offloading work to background processing threads.

So, in the .NET Framework 4.5 Developer Preview, we’ve introduced the new Task.Run method.  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.  It’s a shortcut.  In fact, Task.Run is actually implemented in terms of the same logic used for Task.Factory.StartNew, just passing in some default parameters.  When you pass an Action to Task.Run:

Task.Run(someAction);

that’s exactly equivalent to:

Task.Factory.StartNew(someAction,
    CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);

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).  That doesn’t mean Task.Factory.StartNew will never again be used; far from it.  Task.Factory.StartNew still has many important (albeit more advanced) uses.  You get to control TaskCreationOptions for how the task behaves.  You get to control the scheduler for where the task should be queued to and run.  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.  For the simple cases, though, Task.Run is your friend.

Task.Run provides eight overloads, to support all combinations of the following:

  1. Task vs Task<TResult>
  2. Cancelable vs non-cancelable
  3. Synchronous vs asynchronous delegate

The first two bullets should be self-explanatory.  For the first bullet, there are overloads that return Task (for operations that don’t have a result) and there are overloads that return Task<TResult> (for operations that have a result of type TResult).  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.

The third bullet is more interesting, and is directly related to the async language support in C# and Visual Basic in Visual Studio 11.  Let’s consider Task.Factory.StartNew for a moment, as that will help to highlight what this distinction is.  If I write the following call:

var t = Task.Factory.StartNew(() =>
{
    Task inner =Task.Factory.StartNew(() => {});
    return inner;
});

the type of ‘t’ is going to be Task<Task>; the task’s delegate is of type Func<TResult>, TResult in this case is a Task, and thus StartNew is returning a Task<Task>.  Similarly, if I were to change that to be:

var t = Task.Factory.StartNew(() =>
{
    Task<int> inner = Task.Factory.StartNew(() => 42));
    return inner;
});

the type of ‘t’ is now going to be Task<Task<int>>.  The task’s delegate is Func<TResult>, TResult is now Task<int>, and thus StartNew is returning Task<Task<int>>.  Why is this relevant?  Consider now what happens if I write the following:

var t = Task.Factory.StartNew(async delegate
{
    await Task.Delay(1000);
    return 42;
});

By using the async keyword here, the compiler is going to map this delegate to be a Func<Task<int>>: invoking the delegate will return the Task<int> to represent the eventual completion of this call.  And since the delegate is Func<Task<int>>, TResult is Task<int>, and thus the type of ‘t’ is going to be Task<Task<int>>, not Task<int>.

To handle these kinds of cases, in .NET 4 we introduced the Unwrap method.  Unwrap has two overloads, which are both extensions methods, one on type Task<Task> and one on type Task<Task<TResult>>.  We called this method Unwrap because it, in effect, “unwraps” the inner task that’s returned as the result of the outer task.  Calling Unwrap on a Task<Task> gives you back a new Task (which we often refer to as a proxy) which represents the eventual completion of the inner task.  Similarly, calling Unwrap on a Task<Task<TResult>> gives you back a new Task<TResult> 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’s no result from a task that doesn’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 ‘t’ to represent the return value of that inner task (in this case, the value 42), I could write:

var t = Task.Factory.StartNew(async delegate
{
    await Task.Delay(1000);
    return 42;
}).Unwrap();

The ‘t’ variable will now be of type Task<int>, representing the result of that asynchronous invocation.

Enter Task.Run.  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.  That’s what’s referred to by the third bullet above.  There are overloads of Task.Run that accept Action (for void-returning work), Func<TResult> (for TResult-returning work), Func<Task> (for void-returning async work), and Func<Task<TResult>> (for TResult-returning async work).  Internally, then, Task.Run does the same kind of unwrapping that’s shown with Task.Factory.StartNew above.  So, when I write:

var t = Task.Run(async delegate
{
    await Task.Delay(1000);
    return 42;
});

the type of ‘t’ is Task<int>, and the implementation of this overload of Task.Run is basically equivalent to:

var t = Task.Factory.StartNew(async delegate
{
    await Task.Delay(1000); 
    return 42;
}, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default).Unwrap();

As mentioned before, it’s a shortcut.

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.  If I wanted to offload this work to the ThreadPool and await its result, e.g.

int result = await Task.Run(async () =>
{
    await Task.Delay(1000);
    return 42;
});

the type of result will be int, just as you’d expect, and approximately one second after this work is invoked, the result variable be set to the value 42.

Interestingly, the new await keyword can almost be thought of as a language equivalent to the Unwrap method.  So, if we return back to our Task.Factory.StartNew example, I could rewrite the last snippet above as follows using Unwrap:

int result = await Task.Factory.StartNew(async delegate
{
    await Task.Delay(1000);
    return 42;
}, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default).Unwrap();

or, instead of using Unwrap, I could use a second await:

int result = await await Task.Factory.StartNew(async delegate
{
    await Task.Delay(1000);
    return 42;
}, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);

“await await” here is not a typo.  Task.Factory.StartNew is returning a Task<Task<int>>.  Await’ing that Task<Task<int>> returns a Task<int>, and awaiting that Task<int> returns an int.  Fun, right?

 

   

 

参考:https://devblogs.microsoft.com/pfxteam/task-run-vs-task-factory-startnew/

https://code-maze.com/csharp-task-run-vs-task-factory-startnew/

 

标签:Task,Run,StartNew,await,Factory,task,vs
From: https://www.cnblogs.com/micro-chen/p/17006135.html

相关文章

  • AWVS漏洞扫描器的使用
    前言AWVS是一款强大的web漏洞扫描工具,扫描速度快,可针对特定的漏洞进行扫描测试,用于在按全人员对指定企业进行安全扫描以及测试人员对web应用检测漏洞。AWVS使用以及功能......
  • StoneDB技术观察 | 存算一体 VS 存算分离 ,IT发展下的技术迭代
     存算分离,现在已经成为云原生数据库的标配,开始大规模流行。存算分离后,进一步使计算单元和存储单元解耦,每个单元可以实现单独的动态扩缩容,并且可以通过冗余配置,实现对单点......
  • VScode 使用 emmet
    背景在很多的编辑场合,很多时候回出现很多逻辑性的问题。可能觉得html是一门没有逻辑的语言,实际上,它是有一定的思想编辑的。后来出现了emmet,这个不仅仅是一种快捷方式,同......
  • vs2008调试 Release 工程
    VS2008Release工程调试修改方式:1、项目——》属性——》C/C++——》常规——》调试信息格式——》用于“编辑并继续”的程序数据库(/ZI)2、项目——》属性——》C/......
  • VS2008环境下开发的某些程序在其他机器运行提示“由于应用程序配置不正确,应用程序未能
    比较全的有关vs2008部署问题集(1):http://blog.csdn.net/buhuizheyangba/article/details/7220598比较全的有关vs2008部署问题集(2):http://blog.csdn.net/fengbingchun/artic......
  • vs2010下设置release版本调试设置
    设置在Release模式下调试的方法:1.工程项目上右键->属性2.c++->常规-〉调试信息格式   选 程序数据库(/Zi)或(/ZI),注意:如果是库的话,只能(Zi)3.c++->优化......
  • VS2010中将CString转换为const char*
    最近碰到了CString转constchar*的问题。以前只要简单的一个强制转换就OK了,可现在是不行了,搜索了很多资料,终于搞定,主要是Unicode和ANSI的问题,只要做一个转换就可以了,不......
  • vs中ffmpeg release版本崩溃问题
    vs2010win7下开发视频服务器,用到ffmpeg,debug版本运行正常,切换到release时,出现"0x00905a4d处未处理的异常:0xC0000005:读取位置0x00905a4d时发生访问冲突",原以......
  • Visual Studio 2017(vs2017)绿色便携版-北桃特供
    原版的VisualStudio2017有几十G,安装起来特别慢,不少用户叫苦连天。该版本是精简过的vs2017,且简化了原来的安装程序,特别适用于教学、个人开发者、某些要求不高的企业。该绿......
  • 【数据挖掘】心跳信号分类预测My_Task5 模型融合 笔记
    5.2内容介绍​​https://mlwave.com/kaggle-ensembling-guide/​​https://github.com/MLWave/Kaggle-Ensemble-Guide模型融合是比赛后期一个1重要的环节,大体来说有如下......