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 }
運行上面的代碼咱們發現幾個須要注意的地方:性能
一、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 }
使用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 }
二、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 }
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 }
微軟文檔:
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