一篇文章搞懂同步、异步、阻塞、非阻塞、BIO、NIO和AIO( 二 )


因此和阻塞搭配的词一定是等待 , 和非阻塞搭配的词一定是进行 。
回到程序里 , 阻塞同样意味着停下来等待 , 非阻塞表明可以继续向下执行 。
阻塞和等待等待只是阻塞的一个副作用而已 , 表明随着时间的流逝 , 没有任何有意义的事物发生或进行 。
阻塞的真正含义是你关心的事物由于某些原因无法继续进行 , 因此让你等待 。 但没必要干等 , 你可以做一些其它无关的事物 , 因为这并不影响你对相关事物的等待 。
在堵车时 , 你可以干等 。 也可以玩手机、和别人聊天 , 或者打牌、甚至先去吃饭都行 。 因为这些事物并不影响你对堵车的等待 。 不过你的车必须呆在原地 。
在计算机里 , 是没有人这么灵活的 , 一般在阻塞时 , 选在干等 , 因为这最容易实现 , 只需要挂起线程 , 让出CPU即可 。 在条件满足时 , 会重新调度该线程 。
两两组合所谓同步/异步 , 关注的是能不能同时开工 。
所谓阻塞/非阻塞 , 关注的是能不能动 。
通过推理进行组合:
同步阻塞 , 不能同时开工 , 也不能动 。 只有一条小道 , 一次只能过一辆车 , 可悲的是还TMD的堵上了 。
同步非阻塞 , 不能同时开工 , 但可以动 。 只有一条小道 , 一次只能过一辆车 , 幸运的是可以正常通行 。
异步阻塞 , 可以同时开工 , 但不可以动 。 有多条路 , 每条路都可以跑车 , 可气的是全都TMD的堵上了 。
异步非阻塞 , 可以工时开工 , 也可以动 。 有多条路 , 每条路都可以跑车 , 很爽的是全都可以正常通行 。
是不是很容易理解啊 。 其实它们的关注点是不同的 , 只要搞明白了这点 , 组合起来也不是事儿 。
回到程序里 , 把它们和线程关联起来:
同步阻塞 , 相当于一个线程在等待 。
同步非阻塞 , 相当于一个线程在正常运行 。
异步阻塞 , 相当于多个线程都在等待 。
异步非阻塞 , 相当于多个线程都在正常运行 。
I/OIO指的就是读入/写出数据的过程 , 和等待读入/写出数据的过程 。 一旦拿到数据后就变成了数据操作了 , 就不是IO了 。
拿网络IO来说 , 等待的过程就是数据从网络到网卡再到内核空间 。 读写的过程就是内核空间和用户空间的相互拷贝 。
所以IO就包括两个过程 , 一个是等待数据的过程 , 一个是读写(拷贝)数据的过程 。 而且还要明白 , 一定不能包括操作数据的过程 。
阻塞IO和非阻塞IO应用程序都是运行在用户空间的 , 所以它们能操作的数据也都在用户空间 。 按照这样子来理解 , 只要数据没有到达用户空间 , 用户线程就操作不了 。
如果此时用户线程已经参与 , 那它一定会被阻塞在IO上 。 这就是常说的阻塞IO 。 用户线程被阻塞在等待数据上或拷贝数据上 。
非阻塞IO就是用户线程不参与以上两个过程 , 即数据已经拷贝到用户空间后 , 才去通知用户线程 , 一上来就可以直接操作数据了 。
用户线程没有因为IO的事情出现阻塞 , 这就是常说的非阻塞IO 。
同步IO和同步阻塞IO按照上文中对同步的理解 , 同步IO是指发起IO请求后 , 必须拿到IO的数据才可以继续执行 。
按照程序的表现形式又分为两种:
在等待数据的过程中 , 和拷贝数据的过程中 , 线程都在阻塞 , 这就是同步阻塞IO 。
在等待数据的过程中 , 线程采用死循环式轮询 , 在拷贝数据的过程中 , 线程在阻塞 , 这其实还是同步阻塞IO 。
网上很多文章把第二种归为同步非阻塞IO , 这肯定是错误的 , 它一定是阻塞IO , 因为拷贝数据的过程 , 线程是阻塞的 。
严格来讲 , 在IO的概念上 , 同步和非阻塞是不可能搭配的 , 因为它们是一对相悖的概念 。
同步IO意味着必须拿到IO的数据 , 才可以继续执行 。 因为后续操作依赖IO数据 , 所以它必须是阻塞的 。
非阻塞IO意味着发起IO请求后 , 可以继续往下执行 。 说明后续执行不依赖于IO数据 , 所以它肯定不是同步的 。
因此 , 在IO上 , 同步和非阻塞是互斥的 , 所以不存在同步非阻塞IO 。 但同步非阻塞是存在的 , 那不叫IO , 叫操作数据了 。
所以 , 同步IO一定是阻塞IO , 同步IO也就是同步阻塞IO 。
异步IO和异步阻塞/非阻塞IO按照上文中对异步的理解 , 异步IO是指发起IO请求后 , 不用拿到IO的数据就可以继续执行 。
用户线程的继续执行 , 和操作系统准备IO数据的过程是同时进行的 , 因此才叫做异步IO 。
按照IO数据的两个过程 , 又可以分为两种: