這次要分享的是C#Task任務的幾個列子,感覺最實用的是封裝的分頁任務執行方法,這個方法步奏也是目前在我工作中執行多工常用的,不知道各位也有這用的情況,那麼開始吧。
1.順序任務執行
1 //順序任務執行 2 Task.Factory.StartNew<int>(() => { Console.WriteLine(1); return 1; }). 3 //等待5s以後才會依次輸出2,3 4 ContinueWith((task) => 5 { 6 7 Stopwatch wt = new Stopwatch(); 8 wt.Start(); 9 Thread.Sleep(1000 * 5); 10 wt.Stop(); 11 Console.WriteLine("等待了:{0}ms,輸出結果{1}", wt.ElapsedMilliseconds, 2); 12 }). 13 ContinueWith((task) => { Console.WriteLine(3); }). 14 Wait();
上面的程式碼中也備註了一些文字說明,其中有關鍵詞語及意思如下:
.Task.Factory.StartNew:建立一個Task例項,建立後自動開啟,無需在呼叫Start;
.ContinueWith:看單詞的意思就明瞭,是繼續的意思,在這裡的效果也是等待上一個Task執行完畢了在繼續執行本次任務,這裡方法裡面每個任務是一層一層傳遞的
效果圖:
這裡有個地方注意,sleep這是了5s但是這裡使用Stopwatch統計出來只有4999ms,這個地方存在差異性,本章不解釋,有興趣朋友可以分享下或研究下。
2.並行任務效果
1 //並行任務 2 var watch = new Stopwatch(); 3 //func方法(認知特點:任意長度引數,最後一個的型別是方法返回的返回值型別) 4 Func<object, int> fun = (num) => 5 { 6 Thread.Sleep(1000 * 2); 7 Console.WriteLine("第{0}個", num); 8 return Convert.ToInt32(num); 9 }; 10 var len = 5; 11 var tasks = new Task<int>[len]; 12 //開始計算處理時間 13 watch.Start(); 14 for (int _i = 0; _i < len; _i++) 15 { 16 //Task.Factory.StartNew直接開啟Task任務無需在使用start 17 tasks[_i] = Task.Factory.StartNew<int>(fun, _i); 18 } 19 //10s等待 20 Task.WaitAll(tasks, 1000 * 10); 21 watch.Stop(); 22 Console.WriteLine("tasks共使用時間:{0}s={1}ms", watch.ElapsedMilliseconds / 1000, watch.ElapsedMilliseconds);
關鍵詞語及意思如下:
.Func<object, int>這個是C#新增的特性,這個和Action最大的區別就是Func有返回值,其他的和Action相同任意長度引數個數和型別
.Task.WaitAll這個方法有幾個過載,這裡用的是一個超時時間的方法,設定時間後在規定的時間就不繼續等待Task【】了,如果task【】在超時時間範圍內就執行完了,那麼直接通過,不用再等待超時時間
效果:
這裡依然有統計時間查問題,忽略
3.分頁任務執行方法
1 /// <summary> 2 /// 批次任務執行方法 3 /// </summary> 4 /// <typeparam name="T">引數型別</typeparam> 5 /// <param name="func">func方法</param> 6 /// <param name="list">待執行資料</param> 7 /// <param name="taskLen">任務量</param> 8 /// <param name="timeOut">任務超時時間 預設30s</param> 9 /// <returns></returns> 10 public static int _ExcuteTask<T>(Func<List<T>, int> func, List<T> list, int taskLen = 10, int timeOut = 30) where T : class 11 { 12 var result = 0; 13 //任務量 14 var tasks = new Task<int>[taskLen]; 15 var page = list.Count / taskLen + (list.Count % taskLen > 0 ? 1 : 0); //每個分得得需要執行的總條數 最有一個執行剩餘所有 16 for (var ji = 1; ji <= taskLen; ji++) 17 { 18 //使用分頁方法獲取待執行資料 19 var list01 = list.Skip((ji - 1) * page).Take(page).ToList(); 20 if (list01.Count <= 0) { break; } 21 var task = Task.Run(() => 22 { 23 24 return func(list01); 25 }); 26 tasks[ji - 1] = task; 27 } 28 //等待執行 29 Task.WaitAll(tasks, 1000 * 1 * timeOut); 30 //獲取執行成功條數 31 result = tasks.Where(b => b.IsCompleted).Sum(b => b.Result); 32 33 return result; 34 }
測試程式碼:
1 /// <summary> 2 /// 測試執行底層資料方法 3 /// </summary> 4 /// <param name="list"></param> 5 /// <returns></returns> 6 static int _FuncTest(List<string> list) 7 { 8 9 foreach (var item in list) 10 { 11 Thread.Sleep(1000 * 2); 12 Console.WriteLine("TaskId:{1}輸出第{0}個值", item, Task.CurrentId); 13 } 14 return list.Count; 15 }
1 //分頁任務執行方法 2 var listT = new List<string>(); 3 for (int _i = 0; _i < 9; _i++) 4 { 5 listT.Add(_i.ToString()); 6 } 7 watch.Restart(); 8 //呼叫任務公共方法 9 var result = _ExcuteTask(_FuncTest, listT, 3); 10 watch.Stop(); 11 Console.WriteLine("待處理資料:{0}條,共處理成功資料:{1}條,使用時間:{2}ms", listT.Count, result, watch.ElapsedMilliseconds);
這裡使用的是分頁的原理,把引數集合分發到建立的Task中,使用Task【】來處理這些資料,這裡和第二個例子有點相識就多了分頁寫法而已,最後統計執行成功的條數,以此來返回給呼叫者,方便記錄日誌,此方法目前是我經常使用的,不知道是否還有更好的,各位多多分享,謝謝。
效果圖:
以上就是這次的總結,希望多同學們有些幫助,有疑問或者問題請及時相互交流。