一:什么是异步
当一个方法被调用时立即返回,并获取一个线程执行该方法内部的业务,调用者不用等待该方法执行完毕,我们称这个方法为异步方法。
异步的好处在于非阻塞(调用线程不会暂停执行去等待子线程完成),因此我们把一些不需要立即使用结果、较耗时的任务设为异步执行,可以提高程序的运行效率。net4.0在ThreadPool的基础上推出了Task类,微软极力推荐使用Task来执行异步任务,现在C#类库中的异步方法基本都用到了Task;net5.0推出了async/await,让异步编程更为方便。本篇主要介绍Task、async/await相关的内容。
二:Task介绍
ThreadPool不能控制线程池中线程的执行顺序,也不能获取线程池内线程取消/异常/完成的通知。net4.0在ThreadPool的基础上推出了Task,Task拥有线程池的优点,同时也解决了使用线程池不易控制的弊端。
1、Task创建与运行
1.1 创建task三种方式
Task task = new Task(() => { Console.WriteLine("第一个任务!"); }); task.Start(); Task.Factory.StartNew(() => { Console.WriteLine("第二个任务"); }); Task.Run(() => { Console.WriteLine("第三个任务"); }); Console.WriteLine("执行主线程!");
运行结果:
1.2 带返回值的Task
var task = new Task<string>(() => { return "第一个任务"; }); task.Start(); var task2 = Task<string>.Factory.StartNew(() => { return "第二个任务"; }).Result; var task3 = Task<string>.Run<string>(() => { return "第三个任务"; }).Result; Console.WriteLine(task.Result); Console.WriteLine(task2); Console.WriteLine(task3); Console.WriteLine("执行主线程!"); Console.ReadKey();
运行结果:
1.3 Task同步执行
Task task = new Task(() => { Console.WriteLine("第一个任务!"); }); task.RunSynchronously();
2、Task的阻塞方法(Wait/WaitAll/WaitAny)
task.Wait()、task2.Wait()和Task.WaitAll(task,task2)意义相同
Task.WaitAny(task,task2)执行完任何一个即可执行下面代码
Task task = new Task(() => { Console.WriteLine("第一个任务!"); }); task.Start(); Task task2 = new Task(() => { Console.WriteLine("第二个任务!"); }); task2.Start(); //task.Wait(); //task2.Wait(); Task.WaitAny(task,task2); //Task.WaitAll(task, task2);
3 Task的延续操作(WhenAny/WhenAll/ContinueWith)
WhenAll等待所有任务完成执行延续的操作
WhenAny等待某个任务完成执行延续的操作
ContinueWith延续执行
Task task = new Task(() => { Console.WriteLine("第一个任务!"); }); task.Start(); Task task2 = new Task(() => { Console.WriteLine("第二个任务!"); }); task2.Start(); Task.WhenAny(task, task2).ContinueWith((t) => { Console.WriteLine("延续后执行!"); }); //Task.WhenAll(task, task2).ContinueWith((t) => //{ // Console.WriteLine("延续后执行!"); //}); Console.WriteLine("执行主线程!"); Console.ReadKey();
3、Task的任务取消(CancellationTokenSource)
CancellationTokenSource source = new CancellationTokenSource(); //注册任务取消的事件 source.Token.Register(() => { Console.WriteLine("任务被取消后执行!"); }); int index = 0; //开启一个task执行任务 Task task1 = new Task(() => { while (!source.IsCancellationRequested) { Thread.Sleep(1000); Console.WriteLine($"第{++index}次执行,线程运行中..."); } }); task1.Start(); //延时取消,效果等同于Thread.Sleep(5000);source.Cancel(); source.CancelAfter(5000); Console.ReadKey();
三:异步方法
static void Main(string[] args) { var name = GetNameAsync().GetAwaiter().GetResult(); SaveInfoAsync().GetAwaiter().GetResult(); Console.WriteLine(name); } /// <summary> /// 异步带返回值 /// </summary> /// <returns></returns> static async Task<string> GetNameAsync() { return "wuzhd"; } /// <summary> /// 异步无返回值 /// </summary> /// <returns></returns> static async Task SaveInfoAsync() { }