最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

netcore之异步并不是多线程!

来源:博客园

1、遇到await,线程的变化

遇到await会把当前线程返回且返回值就是await后面的Task,再从线程池随机取一个线程往下执行代码。

我们使用封装好的异步方法模拟写入大量字符串的耗时操作:


(相关资料图)

static async Task Main(string[] args)        {            //原线程            Console.WriteLine(Thread.CurrentThread.ManagedThreadId);            //模拟写入大量字符串的耗时操作            StringBuilder str = new StringBuilder();            for (int i = 0; i < 1000; i++)            {                str.Append("Hello World!");            }            await File.WriteAllTextAsync(@"C:\Users\张跑跑\Desktop\net\async\1.txt", str.ToString());            //异步之后线程            Console.WriteLine(Thread.CurrentThread.ManagedThreadId);        }

结果显示前后线程不一致

那么问题来了,首先会随机到原来的线程吗?答案是会的,发生在异步操作所需时间很少的情况下。现在,我们仅仅把上述代码的循环次数缩短

static async Task Main(string[] args)        {            ......          //降为10次            for (int i = 0; i < 10; i++)            {                str.Append("Hello World!");            }          ......        }

可以看到,线程未改变。(作一个比喻就是,前台(当前线程)放你进店,服务员(新线程)把你领到座位上后忙自己的事,所以你点完菜可能是另一个服务员传,但服务员还没走远,你就点完了菜,那只好她继续上传菜单了)

参考:https://zhuanlan.zhihu.com/p/343235838https://www.cnblogs.com/jiangchengbiao/p/10040899.html

2、异步不等于多线程

自定义的异步方法并不会自动在新线程中执行,除非手动new线程、或者委托、或使用封装好的异步方法

我们模拟一个自定义异步方法

static async Task Main(string[] args)        {            //原线程            Console.WriteLine("原线程:" + Thread.CurrentThread.ManagedThreadId);            double r = await TestAsync();            Console.WriteLine(r);            //异步之后线程            Console.WriteLine("异步后线程:" + Thread.CurrentThread.ManagedThreadId);        }        static async Task TestAsync()        {            //异步中线程            Console.WriteLine("异步后线程:" + Thread.CurrentThread.ManagedThreadId);            double n = 0;            Random random = new Random();            for (int i = 0; i < n * n; i++)            {                n = random.NextDouble();            }            return n;        }

结果是线程未改变

现在我们模拟一个委托

static async Task Main(string[] args)        {            //原线程            Console.WriteLine("原线程:" + Thread.CurrentThread.ManagedThreadId);            double r = await TestAsync1();            Console.WriteLine(r);            //异步之后线程            Console.WriteLine("异步后线程:" + Thread.CurrentThread.ManagedThreadId);        }        static async Task TestAsync()        {            return await Task.Run(() =>            {                //异步中线程                Console.WriteLine("异步后线程:" + Thread.CurrentThread.ManagedThreadId);                double n = 0;                Random random = new Random();                for (int i = 0; i < n*n; i++)                {                    n = random.NextDouble() ;                }                return n;            });        }

可以看到。此时的线程发生了改变

并且注意到,异步中和异步结束后的线程还是一致,前面提到是随机,难道真这么巧?在多次改变for的次数下,貌似不是随机的,难道除了自定义现在连委托也,但具体情况在我的认知盲区!!!我们知道切换线程是要消耗存在大量程序上下文开销,所以就猜想这是net给优化了吧

# async+await 和同步执行有什么好处,都是要一个线程干活,一条龙干到底不好吗,非得自己干到一半交给另一个线程去干,别人干活不用开销吗?这个问题的关键就是有些IO事情真的不需要CPU派一个线程去干,去了也干不了。比如读写文件,以往同步方法时,派一个线程去读写点东西的时候,这个线程肯定是等在那的,读写这个事情是硬盘去做的,线程就是个使者,告诉硬盘要做哪些事就行,硬盘干完活就告诉线程,线程拿着结果开心地继续干下面的活。那异步就是线程通知硬盘去读写后自己就回去该干嘛干嘛去,不必等在硬盘家门口等消息。硬盘读写的时候,这个线程是非阻塞的,可以干其他活,提高效率。硬盘读写完,会通知CPU,叫他派一个线程来拿结果,(如果框架是单线程的,那还是这个线程过来)这个线程拿到结果后会继续执行之前那个线程未干完的活,至于上下文信息,底层会交代好,不在这里讨论,太深。这个IO事情有很多,比如访问数据库,请求网络等。

关键词: 异步方法 有什么好处