首页 > 代码库 > [C#] 异步编程 - 剖析异步方法
[C#] 异步编程 - 剖析异步方法
剖析异步方法
序
这是上篇《开始接触 async/await 异步编程》(入门)的第二章内容,主要是深入了解异步方法,建议大家先看入门篇,很短。
本文要求了解委托的使用。
目录
介绍异步方法
关于 async 关键字:
①在返回类型之前包含 async 关键字
②它只是标识该方法包含一个或多个 await 表达式,即,它本身不创建异步操作。
③它是上下文关键字,即可作为变量名。
现在先来着重分析一下这三种返回值类型:void、Task 和 Task<T>
(1)Task<T>:调用方法要从调用中获取一个 T 类型的值,异步方法的返回类型就必须是Task<T>。调用方法从 Task 的 Result 属性获取的就是 T 类型的值。
1 private static void Main(string[] args) 2 { 3 Task<int> t = Calculator.AddAsync(1, 2); 4 5 //一直在干活 6 7 Console.WriteLine($"result: {t.Result}"); 8 9 Console.Read();10 }
1 internal class Calculator 2 { 3 private static int Add(int n, int m) 4 { 5 return n + m; 6 } 7 8 public static async Task<int> AddAsync(int n, int m) 9 {10 int val = await Task.Run(() => Add(n, m));11 12 return val;13 }14 }
图2
图3
(2)Task:调用方法不需要从异步方法中取返回值,但是希望检查异步方法的状态,那么可以选择可以返回 Task 类型的对象。不过,就算异步方法中包含 return 语句,也不会返回任何东西。
1 private static void Main(string[] args) 2 { 3 Task t = Calculator.AddAsync(1, 2); 4 5 //一直在干活 6 7 t.Wait(); 8 Console.WriteLine("AddAsync 方法执行完成"); 9 10 Console.Read();11 }
1 internal class Calculator 2 { 3 private static int Add(int n, int m) 4 { 5 return n + m; 6 } 7 8 public static async Task AddAsync(int n, int m) 9 {10 int val = await Task.Run(() => Add(n, m));11 Console.WriteLine($"Result: {val}");12 }13 }
图4
图5
(3)void:调用方法执行异步方法,但又不需要做进一步的交互。
1 private static void Main(string[] args) 2 { 3 Calculator.AddAsync(1, 2); 4 5 //一直在干活 6 7 Thread.Sleep(1000); //挂起1秒钟 8 Console.WriteLine("AddAsync 方法执行完成"); 9 10 Console.Read();11 }
1 internal class Calculator 2 { 3 private static int Add(int n, int m) 4 { 5 return n + m; 6 } 7 8 public static async void AddAsync(int n, int m) 9 {10 int val = await Task.Run(() => Add(n, m));11 Console.WriteLine($"Result: {val}");12 }13 }
图6
图7
一、控制流
二、await 表达式
await 表达式指定了一个异步执行的任务。默认情况,该任务在当前线程异步执行。
每一个任务就是一个 awaitable 类的实例。awaitable 类型指包含 GetAwaiter() 方法的类型。
实际上,你并不需要构建自己的 awaitable,一般只需要使用 Task 类,它就是 awaitable。
最简单的方式是在方法中使用 Task.Run() 来创建一个 Task。【注意】它是在不同的线程上运行你的方法。
下面我们来看看示例。
1 internal class Program 2 { 3 private static void Main(string[] args) 4 { 5 var t = Do.GetGuidAsync(); 6 t.Wait(); 7 8 Console.Read(); 9 }10 11 12 private class Do13 {14 /// <summary>15 /// 获取 Guid16 /// </summary>17 /// <returns></returns>18 private static Guid GetGuid() //与Func<Guid> 兼容19 {20 return Guid.NewGuid();21 }22 23 /// <summary>24 /// 异步获取 Guid25 /// </summary>26 /// <returns></returns>27 public static async Task GetGuidAsync()28 {29 var myFunc = new Func<Guid>(GetGuid);30 var t1 = await Task.Run(myFunc);31 32 var t2 = await Task.Run(new Func<Guid>(GetGuid));33 34 var t3 = await Task.Run(() => GetGuid());35 36 var t4 = await Task.Run(() => Guid.NewGuid());37 38 Console.WriteLine($"t1: {t1}");39 Console.WriteLine($"t2: {t2}");40 Console.WriteLine($"t3: {t3}");41 Console.WriteLine($"t4: {t4}");42 }43 }44 }
图2-1
图2-2
上面 4 个 Task.Run() 都是采用了 Task Run(Func<TReturn> func) 形式。
Task.Run() 支持 4 中不同的委托类型所表示的方法:Action、Func<TResult>、Func<Task> 和 Func<Task<TResult>>
1 internal class Program 2 { 3 private static void Main(string[] args) 4 { 5 var t = Do.GetGuidAsync(); 6 t.Wait(); 7 8 Console.Read(); 9 }10 11 private class Do12 {13 public static async Task GetGuidAsync()14 {15 await Task.Run(() => { Console.WriteLine(Guid.NewGuid()); }); //Action16 17 Console.WriteLine(await Task.Run(() => Guid.NewGuid())); //Func<TResult>18 19 await Task.Run(() => Task.Run(() => { Console.WriteLine(Guid.NewGuid()); })); //Func<Task>20 21 Console.WriteLine(await Task.Run(() => Task.Run(() => Guid.NewGuid()))); //Func<Task<TResult>>22 }23 }24 }
三、取消异步操作
四、异常处理
五、在调用方法中同步地等待任务
六、在异步方法中异步地等待任务
七、Task.Delay 方法
小结
--这是Alpha版本--
[C#] 异步编程 - 剖析异步方法