如果一个程序调用某个方法,等待其执行所有处理后才继续执行,我们称这样的方法是同步的。
如果一个程序调用某个方法,在该方法处理完成之前就返回到调用方法,则这个方法是异步的。
异步的好处在于非阻塞,因此我们把一些不需要立即使用结果、较耗时的任务设为异步时,可以提高程序的运行效率。
在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
调用方法调用异步方法时用两个控制流,一是调用方法中,一是异步方法中。
首先调用方法调用异步方法同步地执行异步方法中的代码,直到遇到第一个await表达式(这里控制交给了异步方法)
如果异步方法返回值是Task或Task<T>,异步方法立即创建一个空闲任务返回给调用方法,调用方法不等待异步任务完成(非阻塞)就执行自己内部的代码(这里控制交给调用方法)
当第一个await表达式中任务完成后,异步方法继续执行其内部的代码(控制又交给异步方法)
在遇到下一个await表达式时,重复以上操作,直到遇到return或者执行到异步方法末尾,注意异步方法在结束时并没有返回一个真正的值,它只是退出了。
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 }
原文:https://www.cnblogs.com/wyy1234/p/9172467.html