c#多线程(二)——同步和异步

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

扫描二维码关注公众号,回复: 1569413 查看本文章

  ③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     }

 

猜你喜欢

转载自www.cnblogs.com/wyy1234/p/9172467.html
今日推荐