1. 程式人生 > >c#多線程(二)——同步和異步

c#多線程(二)——同步和異步

沒有 之前 什麽 adk 返回 con bsp cti csu

1、什麽是異步

  如果一個程序調用某個方法,等待其執行所有處理後才繼續執行,我們稱這樣的方法是同步的。

  如果一個程序調用某個方法,在該方法處理完成之前就返回到調用方法,則這個方法是異步的。

異步的好處在於非阻塞,因此我們把一些不需要立即使用結果、較耗時的任務設為異步時,可以提高程序的運行效率。

2、異步方法

2.1 異步方法簡單使用

在C#5.0中出現的async/await可以方便的創建並調用異步方法,async/await特性包括三個部分

  1.調用方法:就是調用異步方法的方法

  2.async方法:異步方法,被調用時立即返回到調用方法

  3.await表達式:在異步方法內部,表示異步執行的任務。一個異步方法可以包含多個await表達式,即一個異步方法可以有多個異步執行的任務。

一個簡單的例子:

 1       static void Main(string[] args)
 2         {
 3             //調用方法是Main,異步方法立即返回
 4             //Task<int>占位符表示把任務放在計劃中,任務最終返回一個int類型的結果
 5             Task<int> value = DoAsyncStuff.CalcSumAsync(5, 6);
 6             //如果執行到這裏異步方法還沒有完成,則阻塞並等待
 7             Console.WriteLine("
result:{0}", value.Result); 8 } 9 } 10 static class DoAsyncStuff 11 { 12 //異步求和,方法簽名用async修飾 13 //異步方法的返回值有三種: 14 //Task<T> 有返回值,返回值的類型為T 15 //Task 無返回值,但是需要監控執行狀態 16 //void 只是調用一下就不管了 17 public static async Task<int> CalcSumAsync(int
a, int b) 18 { 19 //await表達式,表示異步操作的任務 Task.Run()創建一個任務 20 int sum = await Task.Run(() => GetSum(a, b)); 21 return sum; 22 } 23 private static int GetSum(int a, int b) 24 { 25 return a + b; 26 } 27 }

異步方法使用async方法修飾符,方法中有一個或多個await表達式,返回值只有三種

  ①Task<T>:如果調用方法從調用中獲取一個T類型的值,則異步方法的返回值為Task<T>

  ②Task:如果調用方法不需要從異步方法中獲取值,但是需要檢查異步方法的狀態,返回值可以設置為Task

  ③void:如果調用方法只是調用一下異步方法就什麽都不管了,則返回值設為void

2.2 異步方法的控制流

調用方法調用異步方法時用兩個控制流,一是調用方法中,一是異步方法中。

  首先調用方法調用異步方法同步地執行異步方法中的代碼,直到遇到第一個await表達式(這裏控制交給了異步方法)

  如果異步方法返回值是Task或Task<T>,異步方法立即創建一個空閑任務返回給調用方法,調用方法不等待異步任務完成(非阻塞)就執行自己內部的代碼(這裏控制交給調用方法)

  當第一個await表達式中任務完成後,異步方法繼續執行其內部的代碼(控制又交給異步方法)

  在遇到下一個await表達式時,重復以上操作,直到遇到return或者執行到異步方法末尾,註意異步方法在結束時並沒有返回一個真正的值,它只是退出了。

技術分享圖片

2.3 await表達式

2.3.1 await 的使用方法

await表達式指定異步操作的任務,我們可以設置task任務,最常用的方式是:

//1、使用Task.Run新建一個任務
await Task.Run(Func/Action)
//2、執行一個方法,該方法必須是異步方法
await  AsyncFunc

下邊是一個異步求和求差的例子:

 1      class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Task<int> tsum = AsyncStuff.GetSumAsync();
 6             Task<int> tsub = AsyncStuff.GetSubAsync();
 7             //1、等待,直到tsum完成
 8             tsum.Wait();
 9             Task[] tasks = { tsum, tsub };
10             //2、等待,直到tasks都完成
11             Task.WaitAll(tasks);
12             //3、等待,直到tasks中有一個完成
13             Task.WaitAny(tasks);
14 
15             //查看tasks的狀態
16             Console.WriteLine(tsum.Status);
17             Console.WriteLine(tsub.Status);
18             //記錄結果
19             Console.WriteLine(tsum.Result);
20             Console.WriteLine(tsub.Result);
21             Console.ReadKey();
22         }
23     }
24     class AsyncStuff
25     {
26         //異步求和
27         public static async Task<int> GetSumAsync()
28         {
29             int sum = 0;
30             //Task.Run(Func/Action)創建一個任務
31             await Task.Run(() =>
32             {
33                 for (int i = 1; i < 1000000; i++)
34                 {
35                     sum += i;
36                 }
37             });
38             return sum;
39         }
40         //異步求差
41         public static async Task<int> GetSubAsync()
42         {
43             int sub = 0;
44            await Task.Run(() =>
45             {
46                 for (int i = 0; i < 1000000; i++)
47                 {
48                     sub -= i;
49                 }
50             });
51             return sub;
52         }
53     }

  在例子中我們使用Wait、WaitAny、WaitAll實現在調用方法中同步等待任務完成,我們也可以使用WhenAny/WhenAll實現在異步方法中異步地等待任務,這裏不再舉例。

Task.Delay()方法創建一個Task對象,該對象將暫停異步任務的處理,並在一定時間之後完成,與Thread.Sleep不同,Task.Delay不會阻塞線程,線程可以繼續處理其他工作。

一個Task.Delay例子:

 1      class Program
 2     {
 3         static void Main(string[] args)
 4         {           
 5             Simple sp = new Simple();
 6             sp.DoRun();
 7             Console.ReadKey();
 8         }
 9     }
10 
11     class Simple
12     {
13         Stopwatch sw = new Stopwatch();
14         public void DoRun()
15         {
16             sw.Start();
17             Console.WriteLine("Caller:Before call—— {0}",sw.ElapsedMilliseconds);
18             ShowDelyAsync();
19             Console.WriteLine("Caller:After call—— {0}", sw.ElapsedMilliseconds);
20         }
21         public  async void ShowDelyAsync()
22         {
23             Console.WriteLine("Before Delay—— {0}", sw.ElapsedMilliseconds);
24             await Task.Delay(1000);
25             Console.WriteLine("After Delay—— {0}", sw.ElapsedMilliseconds);
26         }
27     }

技術分享圖片

c#多線程(二)——同步和異步