返回目录 html
异步,早期开发人员对它有不少误解,认为不阻塞主线程就是异步,更有认为不阻塞UI就是异步,但异步归根结底和这两个东西关系并不大,异步的出现主要是为了提升线程的利用率,让可用线程更高,而不是一个线程只作一件事,这件事没有完成就不去作下面的事情,这是不正确的,线程应该被解放出来!事实上,你若是学过nodejs的话,对单线程非阻塞应该更清楚一些,它主要经过方法回调来实现异步的,只是在语法上和C#不太同样。node
误解1:不阻塞主线程多线程
若是不阻塞主线程的话,你只能开个新线程完成这个动做,像一些系统通知,它和主线程的工做流程没有关系,若是开个新线程,与主线程并行执行,这并非咱们说的异步,这只是多线程!它会增长线程的开支,使用不当,会影响系统的吞吐量!异步
误解2:不阻塞UIasync
这就更属于胡扯了,对于一个工做流来讲,必需要按着1,2,3的顺序去执行,若是是同步代码,它是一个线程从1执行到3,这个线程将一直被占用!若是是异步代码,它在执行到1时,线程被回收到池子,其它人可使用,当1执行完成后,从线程池里取出一个新的线程继续执行,这叫异步!C#的异步进行友好,使用async,await就能够实现了!测试
实验:查看有效的线程剩余数spa
// <summary> /// 线程非阻塞,线程利用率高 /// 线程await后能够去作其它事 /// 而后await后面方法结束后再申请新线程执行下面的代码 /// </summary> /// <returns></returns> [Route("~/do5")] public async Task<string> Do5() { var sw = new Stopwatch(); sw.Start(); await HttpHelper.Get("http://localhost:61699/do1"); await HttpHelper.Get("http://localhost:61699/do2"); await HttpHelper.Get("http://localhost:61699/do3"); await HttpHelper.Get("http://localhost:61699/do4"); sw.Stop(); int workerThreads, completionPortThreads; ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads); return $"max threads:{workerThreads},completionPortThreads:{completionPortThreads},timer:{sw.ElapsedMilliseconds.ToString()}"; }
咱们来看它的I/O线程剩余,多刷新几回,一直维持在32766和32765之间pwa
而若是使用同步代码,结果就完成不同了,线程剩余各位能够看下面线程
下面是一个更明显的测试,依次执行多个await,而后获取当前线程的ID,它们在异步环境下,有多是不一样的,由于每次都要从池子里拿新的线程!code
await HttpHelper.Get("http://localhost:61699/do1"); str.Append($"step1:{Thread.CurrentThread.ManagedThreadId}"); await HttpHelper.Get("http://localhost:61699/do2"); str.Append($"step2:{Thread.CurrentThread.ManagedThreadId}"); await HttpHelper.Get("http://localhost:61699/do3"); str.Append($"step3:{Thread.CurrentThread.ManagedThreadId}"); await HttpHelper.Get("http://localhost:61699/do4"); str.Append($"step4:{Thread.CurrentThread.ManagedThreadId}");
经过这篇文章,咱们应该真正理解异步这个概念了吧,记住,异步主要为了提升线程利用率,从而提升系统的吞吐量的,它与并行,主线程阻塞颇有直接关系,也不是它所研究的重点,这个你们必定要记住!