为什么 asnyc await 可以提高web程序的吞吐量
(转网上一段话)
Web程序天生就是多线程的,且web线程都是跑的线程池线程(使用线程池线程是为了避免不断创建、销毁线程所造成的资源成本浪费),而线程池线程可使用线程数量是一定的,尽管可以设置,但它还是会在一定范围内。如此一来,我们web线程是珍贵的(物以稀为贵),不能滥用。用完了,那么其他用户请求的时候就无法处理直接503了。
那什么算是滥用呢?比如:文件读取、URL请求、数据库访问等IO请求。如果用web线程来做这个耗时的IO操作那么就会阻塞web线程,而web线程阻塞得多了web线程池线程就不够用了。也就达到了web程序最大访问数。
此时我们的新异步 async await 横空出世,解放了那些原本处理IO请求而阻塞的web线程(想偷懒?没门,干活了。)。通过异步方式使用相对廉价的线程(非web线程池线程)来处理IO操作,这样web线程池线程就可以解放出来处理更多的请求了。
测试代码:
public class TestAsyncController : ApiController { public async void Test(string id) { try { Trace.WriteLine("before the await,the thread id is " + Thread.CurrentThread.ManagedThreadId); await GetData(id); } catch (Exception ex) { Trace.WriteLine(ex); } Trace.WriteLine("after the await,the thread id id " + Thread.CurrentThread.ManagedThreadId); Trace.WriteLine(""); } public Task GetData(string id) { if (id == null) { throw new Exception("抛个异常试试!"); } Trace.WriteLine("before task.run,the thread id is " + Thread.CurrentThread.ManagedThreadId); var tk = Task.Run(() => { Trace.WriteLine("in the task.run,the thread id is " + Thread.CurrentThread.ManagedThreadId); Trace.WriteLine("sleep 3 秒"); Thread.Sleep(3000); Trace.WriteLine("sleep end"); }); Trace.WriteLine("after task.run,the thread id is " + Thread.CurrentThread.ManagedThreadId); return tk; } }
可以看出来, before the await 和 after the await 后的线程ID不一样,说明执行到GetData()方面里面的Task时,web线程就被解放出来了.
如果去掉async 和 await ,在GetData() 方法里面加上 Task.WaitAll(tk) 结果会是什么呢?
public void Test(string id) { try { Trace.WriteLine("before the await,the thread id is " + Thread.CurrentThread.ManagedThreadId); GetData(id); } catch (Exception ex) { Trace.WriteLine(ex); } Trace.WriteLine("after the await,the thread id id " + Thread.CurrentThread.ManagedThreadId); Trace.WriteLine(""); } public Task GetData(string id) { if (id == null) { throw new Exception("抛个异常试试!"); } Trace.WriteLine("before task.run,the thread id is " + Thread.CurrentThread.ManagedThreadId); var tk = Task.Run(() => { Trace.WriteLine("in the task.run,the thread id is " + Thread.CurrentThread.ManagedThreadId); Trace.WriteLine("sleep 3 秒"); Thread.Sleep(3000); Trace.WriteLine("sleep end"); }); Task.WaitAll(tk); Trace.WriteLine("after task.run,the thread id is " + Thread.CurrentThread.ManagedThreadId); return tk; }
结果如下:
before the await 和 after the await 的线程ID 永远一样.说明web线程是一样的