AwaitAsync(异步和多线程)
参考了一些大佬写的文章:
https://www.cnblogs.com/yilezhu/p/10555849.html这个大佬写的文章,我还是很喜欢的
https://www.cnblogs.com/mushroom/p/4575417.html
https://blog.csdn.net/dyllove98/article/details/9735955这篇文章是讨论在.NET中使用进程内COM组件时的公寓模型,以一个示例直观演示STAThread和MTAThread的作用和区别。
C#5.0,.NET Framework4.5
async/await是语法糖,本身就跟编译器提供的功能。
在winform中,是一个STAThread
在winform中使用await/async偶尔会出现一些意外,所以不建议在winform中使用await/async
await/async关键字,在任何一个方法都可以增加async,await放在Task前面,一般成对出现,只有async是没有意义的,有警告,只有await的时候会报错,编译直接报错,await/async要么不用,要么用到底。
主线程调用async/await方法,主线程遇到await返回只能后续动作,await后面的代码会等着task任务完成后再继续执行,await是主线程完成的,其实就像是把await后面的代码包装成一个continue的回调动作,然后这个回调动作也可能是task线程,也可能是新的子线程,也可能是主线程。
一个async方法,如果没有返回值,可以方法声明返回Task
private static async Task<long> SumAsync() { Console.WriteLine($"SumAsync 111 start ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); long result = 0; await Task.Run(() => { for (int k = 0; k < 10; k++) { Console.WriteLine($"SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); Thread.Sleep(1000); } for (long i = 0; i < 999_999_999; i++) { result += i; } }); Console.WriteLine($"SumFactory 111 end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); await Task.Run(() => { for (int k = 0; k < 10; k++) { Console.WriteLine($"SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); Thread.Sleep(1000); } for (long i = 0; i < 999999999; i++) { result += i; } }); Console.WriteLine($"SumFactory 111 end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); await Task.Run(() => { for (int k = 0; k < 10; k++) { Console.WriteLine($"SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); Thread.Sleep(1000); } for (long i = 0; i < 999999999; i++) { result += i; } }); Console.WriteLine($"SumFactory 111 end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); return result; }
Task<long> t = SumAsync(); Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
有了await之后,在这个方法中,代码是按照顺序从上往下执行的,但是,为什么不直接写一个同步方法,还要写await呢?
如果不写await的话,Task.Run()会开启一个线程,不会足额色主线程,这样在最后的结果result就是0了。
await/async能够用同步的方式编写代码,但是又是非阻塞的。
原理探究和使用建议:
public class AwaitAsyncILSpy { public static void Show() { Console.WriteLine($"start1 {Thread.CurrentThread.ManagedThreadId.ToString("00")}"); Async(); Console.WriteLine($"aaa2 {Thread.CurrentThread.ManagedThreadId.ToString("00")}"); } public static async void Async() { Console.WriteLine($"ddd5 {Thread.CurrentThread.ManagedThreadId.ToString("00")}"); await Task.Run(() => { Thread.Sleep(500); Console.WriteLine($"bbb3 {Thread.CurrentThread.ManagedThreadId.ToString("00")}"); }); Console.WriteLine($"ccc4 {Thread.CurrentThread.ManagedThreadId.ToString("00")}"); } }
AwaitAsyncLibrary.AwaitAsyncILSpy.Show(); Console.WriteLine("hello word!");
这样的代码,输出的顺序是是什么?
await/async能够用同步的方式编写代码,但又是非阻塞的
async方法在编译之后会生成一个状态机(实现了IAsyncStateMachine接口)
状态机:初始化状态----执行就修改状态1-----再执行就修改状态变为0-----执行就修改状态变为1----如果出现其他状态就结束了。
就像是红绿灯那样,永远的死循环下去。
async方法里面的逻辑其实都放在了MoveNext----主线程new一个状态机1-----主线程调用MoveNext-----指向了await之前的东西----启动Task----主线程改状态为0----回去干自己的事了-----子线程Movenext----状态又回归-1了-----再执行后续的逻辑------如果需要还可以继续循环。
原文地址:https://www.cnblogs.com/lonelyxmas/p/11560260.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Mycat分库分表全解析 Part 1 数据库切分概述
- RoarCTF2019-EasyJava
- ACTF2020新生赛-BackupFile
- DB2 Linux平台安装 Part 5 数据库常见参数配置
- GXYCTF2019-PingPingPing
- 利用cloudflareWorkers制作Google镜像站
- MySQL information_schema详解 COLLATIONS
- 极客大挑战2019-Knife
- DB2备份还原相关操作
- MySQL复制全解析 Part 8 MySQL Auto-Positioning
- Redis 5.0.8 主从搭建
- Linux 修改网卡名称及mac地址
- MySQL Galera Cluster全解析 Part 10 grastate.dat文件详解
- MySQL MHA部署 Part 7 MHA手动切换测试
- 使用sysbench进行压测 Part2 sysbench语法介绍