对网站建设服务公司的看法,wordpress主题自定义打不开,黄岛网站建设设计公司,内蒙古工程建设招投标中心网站在我们 2015 年开始的从 .NET Framework 向 .NET Core 迁移的工程中#xff0c;遇到的最大的坑就是标题中所说的——同步方法中调用异步方法发生”死锁”。虽然在 .NET Framework 时代就知道不能在同步方法中调用异步方法#xff0c;但我们却明知路有坑#xff0c;偏向此路行… 在我们 2015 年开始的从 .NET Framework 向 .NET Core 迁移的工程中遇到的最大的坑就是标题中所说的——同步方法中调用异步方法发生”死锁”。虽然在 .NET Framework 时代就知道不能在同步方法中调用异步方法但我们却明知路有坑偏向此路行。不是我们自讨苦吃而是被迫无奈因为在 .NET Core 2.0 之前BCL基础类库中有些 API 只有异步实现没有同步实现比如用于将主机名解析为 IP 地址的 API —— Dns.GetHostAddressesAsync() 。但最终“被迫无奈”变成“血的教训”这根本不是坑而是无底洞。无论在开发与测试环境中多么正常只要一发布到生产环境有一定并发量就会发生“死锁” —— 大量请求无响应一直处于等待状态线程池发飙线程数持续不断地增长内存随之增长直至撑爆服务器详见当时的一篇随笔 .NET Core 中遇到奇怪的线程死锁问题内存与线程数不停地增长。我们想尽一切方法用尽网上能找到的同步方法调用异步方法避免死锁的办法都于事无补唯有去掉同步方法调用异步方法的代码。当我们意识这是一个无底洞后赶紧绕道而行全面放弃在同步方法中调用异步方法并将“千万千万不要在同步方法中调用异步方法”作为一条 .NET Core 开发准则。这段踩坑踩到无底洞的血泪史每当想起都很心痛心痛不是当时的任何努力都是那么的苍白无力而是对问题背后原因的困惑 —— 为什么同步方法中 Wait 异步方法会产生如此致命的后果如果真的千万千万不能这么干那 .NET Core 为什么不直接在编译时就报错“死锁”的背后究竟发生了什么。。。2018年10月20日偶然间发现一个网站 —— dotNET Weekly 在其中发现一篇10月17日发布的博文 —— .NET Threadpool starvation, and how queuing makes it worse在读懂这篇博文之后联系到之前踩坑的经历终于想通了“死锁”的背后只是个人推测并不一定正确。.NET Core 线程池有 n1 个队列每个线程有自己的本地队列n整个线程池有一个全局队列1。每个线程接活从队列中取出任务执行的顺序是这样的先从自己的本地队列中找活 - 如果本地队列为空则从全局队列中找活 - 如果全局队列为空则从其他线程的本地队列中抢活。我们来想象一下异步方法等待同步方法的场景。当10个并发请求到达时进入的是全局队列假设线程池中正好有10个空闲线程这10个线程立马把活接过来但线程在执行过程中遇到了同步方法等待异步方法Task.Wait的情况而进入阻塞状态无奈地无所事事地在那干等异步方法执行完成而无法帮其他线程干活这时情况已经有些不妙由于阻塞线程池少了10个干活的线程。雪上加霜的是这些阻塞的线程所等待的异步方法在完成异步操作执行 await 之后的代码时也需要线程不仅干活的线程少了而且剩下的线程要干的活更多了情况更不妙了。随着并发请求持续不断地进来形势变得越来越严峻被阻塞的线程越来越多能干活的线程越来越少而且要干的活越来越多于是越来越多的一线干活的线程的队列开始排起了长队。火上浇油的是那些阻塞着的线程要退出阻塞状态需要等它们所等待的任务被正忙得不可开交的干活线程执行干活线程越忙它们被阻塞的时间越长。于是出现了一个奇怪的场面一群不干活的线程围观并等待着少数干活的线程眼看着这些干活线程的队列排队越来越长虽然它们也能干活但由于它们被关在小黑屋里无法出手相助要等它们的主人将它们释放出来而它们的主人就排在长队中等着从干活线程那拿到小黑屋的钥匙。。。这样的场面最终只有一个结局所有干活的线程的本地队列都排起了长队没有空闲的线程。好戏开始了不是灾难开始了。线程池中没有空闲线程全局队列中的活没人接于是全局队列开始排队线程池的线程不够用如果不赶紧补充线程进来线程池会被饿死Threadpool Starvation。救援行动开始了CLR 赶紧生产线程喂给线程池由于全局队列享有最高优先级根据之前所述的线程接活顺序一喂进去就被全局队列吃了但 CLR 一秒钟只能生产1-2个线程远远满足不了全局队列的胃口而最需要救援的各个干活线程的本地队列连汤都喝不到。除了 CLR 的外部救援线程池也同时进行自救有些线程玩命干活终于处理完了自己队列中的任务终于有机会可以帮助其他同伴了但是它们立即接到了上级命令 —— 以最快速度去救援全局队列军令不可违它们眼睁睁地看着同伴绝望地处理着一望无际的长队中的任务奔赴全局队列自救也救不到干活线程的本地队列。这种完全以全局队列为中心、救地位最高的、不救最需要的救援行动最终带来了毁灭性的结果。那些解救全局队列的线程又因为 Task.Wait 而阻塞而需要更多的线程执行阻塞所等待的任务。救援行动变成了自杀行动线程池就这样被活活饿死了Threadpool Starvation。这就是我所推测的真相真相背后的真正罪魁祸首其实是对线程的阻塞所以千万千万不要阻塞blocking线程。原文地址https://www.cnblogs.com/dudu/p/9860959.html.NET社区新闻深度好文欢迎访问公众号文章汇总 http://www.csharpkit.com