C# Task TaskFactory 異步線程/異步任務

Task是.NetFramework3.0出現的,線程是基於線程池,而後提供了豐富的API數據庫

TaskFactory  提供對建立和計劃 Task 對象的支持api

建立和啓動異步任務緩存

一、Task task = new Task(() => ThreadPoolHelper.DoSomeThing());
      task.Start();多線程

二、Task task = Task.Run(() => ThreadPoolHelper.DoSomeThing());併發

三、TaskFactory taskFactory = Task.Factory;異步

      Task task = taskFactory.StartNew(() => ThreadPoolHelper.DoSomeThing());分佈式

Task的線程是源於線程池 ,假如說我想控制下Task的併發數量,該怎麼作?ide

 1             {
 2                 //ThreadPool.SetMaxThreads(8, 8);
 3                 //線程池是單例的,全局惟一的
 4                 //設置後,同時併發的Task只有8個;並且線程是複用的;
 5                 //全局的,請不要這樣設置!!!
 6                 for (int i = 0; i < 100; i++)
 7                 {
 8                     int k = i;
 9                     Task.Run(() =>
10                     {
11                         Console.WriteLine($"This is k={k},i={i} running ThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
12                         Thread.Sleep(2000);
13                     });
14                 }
15             }
View Code

運行上面的代碼咱們發現幾個須要注意的地方:性能

一、i的值等於100,由於異步線程的啓動並不阻塞主線程;優化

二、使用ThreadPool.SetMaxThreads 方法 設置後,雖然能達到效果,可是線程池是單例的,全局惟一的,這樣設置會影響整個程序;

那麼如何實現?

 1             {
 2                 List<Task> taskList = new List<Task>();
 3                 for (int i = 0; i < 10000; i++)
 4                 {
 5                     int k = i;
 6                     if (taskList.Count(t => t.Status != TaskStatus.RanToCompletion) >= 20)
 7                     {
 8                         Task.WaitAny(taskList.ToArray());
 9                         taskList = taskList.Where(t => t.Status != TaskStatus.RanToCompletion).ToList();
10                     }
11                     taskList.Add(Task.Run(() =>
12                     {
13                         Console.WriteLine($"This is {k} running ThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
14                         Thread.Sleep(2000);
15                     }));
16                 }
17             }
View Code

使用Parallel也能夠實現

Task經常使用方法

一、Delay(Int32)、Delay(Int32, CancellationToken)、Delay(TimeSpan)、Delay(TimeSpan, CancellationToken)

在指定的時間後執行任務

1             {
2                 Stopwatch stopwatch = new Stopwatch();
3                 stopwatch.Start();
4                 Console.WriteLine("在Delay以前");
5                 Task.Delay(2000).ContinueWith(t => { Console.WriteLine($"Delay耗時ContinueWith Start{stopwatch.ElapsedMilliseconds}"); ThreadPoolHelper.DoSomeThing(); Console.WriteLine($"Delay耗時ContinueWith End{stopwatch.ElapsedMilliseconds}"); });
6                 Console.WriteLine($"Delay耗時{stopwatch.ElapsedMilliseconds}");
7             }
View Code

二、ContinueWith(Action<Task,Object>, Object)、ContinueWith(Action<Task>)、ContinueWith<TResult>(Func<Task,Object,TResult>, Object, CancellationToken, TaskContinuationOptions, TaskScheduler)、...

目標任務完成後異步執行一個延續任務

三、Wait()、Wait(CancellationToken)、Wait(Int32)、Wait(Int32, CancellationToken)、Wait(TimeSpan)

等待任務或通過指定時間爲止  與Thread.Join方法、waitHandle.WaitOne方法 做用至關

四、WaitAll(Task[])、WaitAll(Task[], CancellationToken)、WaitAll(Task[], Int32)、WaitAll(Task[], Int32, CancellationToken)、WaitAll(Task[], TimeSpan)

等待全部任務對象完成執行或通過指定時間爲止,或等到取消等待

五、WaitAny(Task[])、WaitAny(Task[], CancellationToken)、WaitAny(Task[], Int32)、WaitAny(Task[], Int32, CancellationToken)、WaitAny(Task[], TimeSpan)

等待全部任務對象任何一個任務對象完成執行或通過指定時間爲止,或等到取消標記取消

六、WhenAll(IEnumerable<Task>)、WhenAll(Task[])、WhenAll<TResult>(IEnumerable<Task<TResult>>)、WhenAll<TResult>(Task<TResult>[])

全部任務對象都已完成時,建立一個新的任務並執行

七、WhenAny(IEnumerable<Task>)、WhenAny(Task[])、WhenAny<TResult>(IEnumerable<Task<TResult>>)、WhenAny<TResult>(Task<TResult>[])

全部任務對象任何一個任務完成就建立一個新的任務並執行

TaskFactory經常使用方法

一、ContinueWhenAll(Task[], Action<Task[]>)、ContinueWhenAll(Task[], Action<Task[]>, CancellationToken)、ContinueWhenAll(Task[], Action<Task[]>, CancellationToken, TaskContinuationOptions, TaskScheduler)、...

全部任務對象都已完成時,建立一個新的任務並執行   與Task.WhenAll方法 做用至關

二、ContinueWhenAny(Task[], Action<Task>)、ContinueWhenAny<TAntecedentResult>(Task<TAntecedentResult>[], Action<Task<TAntecedentResult>>)、...

全部任務對象任何一個任務完成就建立一個新的任務並執行 與Task.WhenAny方法 做用至關

 

那麼何時能用多線程? 任務能併發的時候

多線程能幹嗎?提高速度/優化用戶體驗

網站首頁:A數據庫 B接口 C分佈式服務 D搜索引擎,適合多線程併發,都完成後才能返回給用戶,須要等待WaitAll
列表頁:核心數據可能來自數據庫/接口服務/分佈式搜索引擎/緩存,多線程併發請求,哪一個先完成就用哪一個結果,其餘的就無論了

現實實例

多人合做開發---多線程--提高效率/性能

 1             {
 2                 TaskFactory taskFactory = new TaskFactory();
 3                 List<Task> taskList = new List<Task>();
 4                 taskList.Add(taskFactory.StartNew(o=> Coding("A", " Portal"), "A"));
 5                 taskList.Add(taskFactory.StartNew(o=> Coding("B", "    DBA"), "B"));
 6                 taskList.Add(taskFactory.StartNew(o=> Coding("C", " Client"), "C"));
 7                 taskList.Add(taskFactory.StartNew(o=> Coding("D", "Service"), "D"));
 8                 taskList.Add(taskFactory.StartNew(o=> Coding("E", " Wechat"), "E"));
 9 
10                 //誰第一個完成,獲取一個紅包獎勵
11                 taskFactory.ContinueWhenAny(taskList.ToArray(), t => Console.WriteLine($"{t.AsyncState}開發完成,獲取個紅包獎勵{Thread.CurrentThread.ManagedThreadId.ToString("00")}"));
12                 //實戰做業完成後,一塊兒慶祝一下
13                 taskList.Add(taskFactory.ContinueWhenAll(taskList.ToArray(), rArray => Console.WriteLine($"開發都完成,一塊兒慶祝一下{Thread.CurrentThread.ManagedThreadId.ToString("00")}")));
14                 //ContinueWhenAny  ContinueWhenAll 非阻塞式的回調;並且使用的線程多是新線程,也多是剛完成任務的線程,惟一不多是主線程
15 
16 
17                 //阻塞當前線程,等着任意一個任務完成
18                 Task.WaitAny(taskList.ToArray());//也能夠限時等待
19                 Console.WriteLine("準備環境開始部署");
20                 //須要可以等待所有線程完成任務再繼續  阻塞當前線程,等着所有任務完成
21                 Task.WaitAll(taskList.ToArray());
22                 Console.WriteLine("5個模塊所有完成後,集中調試");
23 
24                 //Task.WaitAny  WaitAll都是阻塞當前線程,等任務完成後執行操做
25                 //阻塞卡界面,是爲了併發以及順序控制
26             }
View Code
 1         /// <summary>
 2         /// 模擬Coding過程
 3         /// </summary>
 4         /// <param name="name"></param>
 5         /// <param name="projectName"></param>
 6         private static string Coding(string name, string projectName)
 7         {
 8             Console.WriteLine($"****************Coding Start  {name} {projectName}  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
 9             long lResult = 0;
10             for (int i = 0; i < 1_000_000_000; i++)
11             {
12                 lResult += i;
13             }
14             Console.WriteLine($"****************Coding   End  {name} {projectName} {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} {lResult}***************");
15             return name;
16         }
View Code

微軟文檔:

Task:https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.tasks.task?view=netframework-4.8

TaskFactory:https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.tasks.taskfactory?view=netframework-4.8

相關文章
相關標籤/搜索