一、异步编程
使用await不要用Result
async/await主要用于创建异步方法,防止阻塞当前线程。
当一个线程遇到await时,会在await修饰的逻辑启用新线程(执行异步逻辑)时,直接释放本线程,使用新线程去执行该语句和后续语句。即不阻塞当前线程,只占用1个线程。
例如:
Task.Run(async () => {
var result = await Task.Run(() => { Thread.Sleep(3000);
return "qaz"; }); });
代码是在线程里await执行一个异步方法。
断点打在
return "qaz";
处,调试如下
可以看出除了主线程外,只有一个工作线程。即外层的线程直接被释放。
当用Result属性时,线程会被阻塞等待,而不是释放
Task.Run(async () => {var result = Task.Run(() => { Thread.Sleep(3000);return "qaz"; }).Result; });
有个托管ID=3的线程在等待,它就是外层线程,导致占用了2个线程
二、线程池
最小线程池个数是CPU
的核心数,最大线程池个数是32767
。dotnet
生成新线程的规则是,当有新任务需要线程时,先在线程池中找空闲线程,如果没有空闲,就等待500ms
看是否有线程空闲出来,如果还是没有,产生一个新线程。
比如4核服务器的线程数就是4
ThreadPool.ThreadCount: 4, Minimum work threads: 4, Minimum completion port threads: 4
而这点线程对高并发应用来说都不够塞牙缝。虽然 ASP.NET Core runtime 会在线程不够用时自动创建线程,但是每秒只能创建1-2个线程,线程数增加也很慢,导致很多请求被拒绝。
后来想通过将线程池的最小线程数调大去解决问题,但是设置1k以上时,SetMinThreads返回值为false,设置不生效。
需用SetMaxThreads先设置最大线程数,之后再SetMinThreads设置最小线程数。奇迹这样发生了……
而且更诡异的是SetMaxThreads设置一个比以前小的值,之后再调用SetMinThreads设置最小线程数也是OK的。
设置OK之后程序虽然程序的线程数并不会立马增加,但是一旦遇到高并发请求,线程数增加是非常快速的。差不多1秒几十个线程左右。当并发量降低之后,线程数也会降低。但是当并发再次增高的时候,线程数的增加会比之前更快(一两秒就能恢复到2k水平)