Task三個列子的分享

神牛003發表於2016-05-24

這次要分享的是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();
View Code

  上面的程式碼中也備註了一些文字說明,其中有關鍵詞語及意思如下:

  .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);
View Code

  關鍵詞語及意思如下:

  .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         }
View Code

  測試程式碼:

 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         }
View Code
 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);
View Code

  這裡使用的是分頁的原理,把引數集合分發到建立的Task中,使用Task【】來處理這些資料,這裡和第二個例子有點相識就多了分頁寫法而已,最後統計執行成功的條數,以此來返回給呼叫者,方便記錄日誌,此方法目前是我經常使用的,不知道是否還有更好的,各位多多分享,謝謝。

  效果圖:

  

  以上就是這次的總結,希望多同學們有些幫助,有疑問或者問題請及時相互交流。

相關文章