先看下面例子
同步阻塞:
令狐冲泡妹纸 ,打电话给妹纸 , 妹纸没有回应,令狐冲想我现在还不会独孤九剑,还不够NB,就老实点,令狐冲就一直等下去
同步非阻塞
令狐冲拍妹纸 , 打电话给妹纸 , 妹纸没有回应 , 令狐冲想老子猪脚光环,等会妹纸肯定会再打给我的,然后令狐冲就每隔10分钟瞅一眼电话。
异步阻塞
令狐冲泡妹纸 , 打电话给妹纸 , 妹纸没回应 , 然后令狐冲让林平之去等电话,妹纸打过来了 , 就让自己来接,然后令狐冲一直等林平之
异步非阻塞
令狐冲泡妹纸 , 打电话给妹纸 , 妹纸没回应 , 然后令狐冲让林平之去等电话,妹纸打过来了 , 就让自己来接,然后令狐冲去泡别的妹纸去了
这样看来 同步/异步 是电话的通知方式 阻塞和非阻塞是令狐冲这个逗逼的等待方式
同步和异步 是指API被调用者的通知方式
阻塞和非阻塞 是指API调用者的等待方式
而在不同场景下 同步/异步 阻塞/非阻塞 四种组合都有应用
同步阻塞 简单列子就如我们在C中调用某个库函数并等待返回
同步非阻塞 就是 “每隔一会瞄一眼电话”的轮询(polling)方式
同步非阻塞方式比同步阻塞方式对比:
优点是能够在等待任务完成的时间里干其他活。
缺点是任务完成的相应延迟增大了,因为每过一段时间才去轮询一次,而任务可能在两次轮询之间的任意时间完成
由于同步非阻塞方式需要不断轮询,而“后台”可能有多个任务在同时进行,我们就想到了循环查询多个任务的完成状态,只要有一个任务完成,就去处理它。
这就是所谓的“I/O多路复用”。
UNIX/LINUX下的select、poll、epoll就是基于“I/O多路复用”机制的。windows下则有WaitForMultipleObjects和IO Completion Ports API (IOCP)
高并发的程序一般使用同步非阻塞方式 而非 多线程+同步阻塞方式
说到这里,就要谈到并发和并行的区别。比如春节期间的抢票大战,买票人数就是并发数,而售票窗口就是并行数。也就是说并发数是指同事进行的任务数(如同时服务的HTTP请求),而并行数是可以同时工作的物理资源数量(如CPU核数)
通过合理调度任务的不同阶段,并发数可以远远大于并行数,这就是为什么单机上多核CPU能够同事支持上W个请求的原因。在这种高并发的情况下,每个任务创建一个进程或者线程的开销非常大。而同步非阻塞的方式可以把多个I/O的请求丢到后台去,这就可以在一个进程里服务大量的并发I/O请求。