一個Task表示一個異步操作,Task的創建和執行都是獨立的,因此可以對關聯操作的執行擁有完全的控制權。
一:Task的優勢
1: Task支持線程的取消、完成、失敗通知等交互性操作
2: Task支持線程執行的先后次序
Task t = new Task(() => { }); t.ContinueWith((task) => { }); t.Start();
二:Task的完成狀態
任務Task有這樣一些屬性,讓我們查詢任務完成時的狀態:
1: IsCanceled,因為被取消而完成
2: IsCompleted,成功完成
3: IsFaulted,因為發生異常而完成
CancellationTokenSource cts = new CancellationTokenSource(); Task<int> t = new Task<int>(() => Add(cts.Token), cts.Token); t.Start(); t.ContinueWith(TaskEnded); //等待按下任意一個鍵取消任務 Console.ReadKey(); cts.Cancel();
任務Task創建方式
方式一、new Task 無返回值
Task task = new Task(() =>{}); task.Start();
new Task 有返回值的方式,Task 與 ContinueWith
//先執行Task Task<int> task = new Task<int>(() => { return 0; }); //其次執行ContinueWith task.ContinueWith(t => { int result = t.Result; }); task.Start();
方式二、使用 TaskMethod 無返回值
Task task = new Task(() => TaskMethod("Task 2")); task.Start();
方式三、Task.Run
Task task = Task.Run(() => TaskMethod("Task 3"));
方式四、直接異步的方法
Task.Factory.StartNew(() => TaskMethod("Task 3"));
方式五、異步
Task.Run(async () => { await Task.Factory.StartNew(() => { }); });
Task任務並行
List<Task> taskList = new List<Task>(); taskList.Add(Task.Run(() => { })); taskList.Add(Task.Run(() => { })); taskList.Add(Task.Run(() => { }));
//主線程阻塞,等待結束
Task.WaitAll(taskList.ToArray());
主線程 Code ....執行
方式三、異步非阻塞
Task[] tlist = new Task[] { Task.Factory.StartNew(() => { Thread.Sleep(3000); }), Task.Factory.StartNew(() => { Thread.Sleep(90000); }) }; Task.WhenAny(tlist).ContinueWith((s) => { return s; });
使用IProgress實現異步編程的進程通知
private void btnSub_Click(object sender, RoutedEventArgs e) { Task task = Display(); } void DoProcessing(IProgress<int> progress) { if (progress != null) { progress.Report(1); } } async Task Display() { //當前線程 var progress = new Progress<int>(percent => { this.Title = percent.ToString(); }); //線程池線程 await Task.Run(() => DoProcessing(progress)); }
本文來源參考:https://www.cnblogs.com/zhaoshujie/p/11082753.html
什么是並行
並行是指兩個或者多個事件在同一時刻發生
在程序運行中,並行指多個CPU核心同時執行不同的任務;對於單核心CPU,嚴格來說是沒有程序並行的。並行是為了提高任務執行效率,更快的獲取結果。
與並發的區別
並發是指兩個或者多個事件在同一時段發生。
相對於並行,並發強調的是同一時段,是宏觀上的同時發生。實際上,同一時刻只有一個任務在被執行,多個任務是分時地交替執行的。並發是為了更合理地分配資源。
實現並行,我們要借助進程和線程。
進程是正在運行的程序的實例。
線程被包含在進程之中,是進程中的實際運作單位。
前台線程和后台線程
.NET把線程分為前台線程和后台線程,兩者幾乎相同,唯一的區別是,前台線程會阻止進程的正常退出,后台線程則不會。
線程池 ThreadPool
線程的創建和銷毀要耗費很多時間,而且過多的線程不僅會浪費內存空間,還會導致線程上下文切換頻繁,影響程序性能。為改善這些問題,.NET運行時(CLR)會為每個進程開辟一個全局唯一的線程池來管理其線程。
多線程
1、在執行一個較長時間的任務時,不能阻塞UI界面響應,必須通過后台線程處理;
2、在執行批量計算密集型任務時,采用多線程技術可以提高運行效率;
傳統使用的多線程技術有:
Thread & ThreadPool
Timer
BackgroundWorker
Task內部也是對ThreadPool的封裝
采用並行編程方法:
Parallel.For(1, 10000, x=>
{
bool b = IsPrimeNumber(x);
Console.WriteLine($"{i}:{b}");
});
//使用並行循環處理數據更新
List<string> lists = new List<string>();
System.Threading.Tasks.Parallel.For(0, lists.Count, (int i) =>
{
string sql = string.Format("update table1 set IsExit =1 where Id='{0}'", lists[i]);
Execute(sql);
});
和Task類似,Parallel類仍然是對ThreadPool的封裝。
需要通知一個任務結束,或一個任務等待某個條件進入下一個狀態,這就需要用到任務同步的技術。
采用WaitOne來等待
異步編程模型(await、async)
非UI線程不能訪問UI控件,可以使用Invoke
多線程環境下的數據安全
private static ConcurrentDictionary<int, string> Dic = new ConcurrentDictionary<int, string>();
//添加操作
Dic.TryAdd(i, i.ToString());
多線程的異常處理
基本原則:不要輕易捕獲根異常;
多線程的內部異常不會傳播到主線程,應該在內部進行處理,可以通過事件推到主線程來;
應用程序層面可以捕獲根異常,做一些記錄工作,切不可隱匿異常。
將異常包裝成事件推送到主線程,交給主線程處理。
參考:https://www.cnblogs.com/seabluescn/p/12973936.html
異步編程中,線程之間只要互不影響,考慮同步問題即可。而在並行編程中,則要求多個線程在同一時刻同時運行。