C# async 和 await 理解先假设如下场景: 主函数 Main,循环等待用户输入; 计算函数 Cal,耗时计算大量数据; class Test { static int Main(string[] args) { while(true) { // 等待用户输入 } } public static int Cal() { int sum = 0; for (int i = 0; i < 999; i++) { sum = sum + i; } Console.WriteLine($'sum={sum}'); return sum; }}
为了在Main函数中调用Cal函数,同时Cal函数不阻塞主函数的循环,此时需要考虑增加一个CalAsync函数使Cal函数异步执行。 传统的思维方法
这种方法显示地创建了一个线程并启动执行,CalAsync函数本身还是在主线程执行并且无法直接获取Cal函数的结果。 async 和 await 异步编程方法 // using System.Threading.Tasks;public static aysnc void CalAsync(){ int result = await Task.Run(new Func<int>(Cal)); // 或使用lambda书写方式 // int result = await Task.Run(() => test()); Console.WriteLine(result);}
在Main函数中直接调用CalAsync函数,可以发现CalAsync成功调用了Cal函数并在一段时间后输出了结果,同时Main函数并不会被阻塞。 分别在Main、Cal、CalAsync函数中增加代码打印当前线程ID:
结果如图: 可以看出,在CalAsync函数中,await标记之前,代码在主线程中执行,而await标记之后,代码在子线程中执行。 理解与结论:
public static async Task<int> CallCalAsync() { string tid = Thread.CurrentThread.ManagedThreadId.ToString(); Console.WriteLine($'CallCalAsync1 tid {tid}'); int result = await CalAsync(); tid = Thread.CurrentThread.ManagedThreadId.ToString(); Console.WriteLine($'CallCalAsync2 tid {tid}, result={result}'); return result; }
总结C#中async与await异步编程,可以理解为: 1. async声明了一个包含异步执行代码的函数,该函数执行时不会阻塞调用线程; 2. await存在于async函数中,声明了一个异步执行入口,程序动态运行时从该入口创建并进入一个异步线程环境,并在该线程执行任务实例及任务实例返回之后的代码; 3. 一个async函数中声明多个await关键字时,程序将代码顺序创建并进入异步子线程执行任务实例及任务实例返回之后的代码直到下一个await声明处, 最后一个await声明之后的代码会在最后一个异步子线程中执行 ; 3. await标记的右侧代码返回或定义了一个任务实例,该实例由需要异步执行的目标耗时函数初始化,并在最终定义处触发异步执行。 |
|