首先先通过一些简单的案例了解以下几个概念:

洗衣机洗衣服

洗衣机洗衣服(无论阻塞式IO还是非阻塞式IO,都是同步IO模型)

  • 同步阻塞:你把衣服丢到洗衣机洗,然后看着洗衣机洗完,洗好后再去晾衣服(你就干等,啥都不做,阻塞在那边)
  • 同步非阻塞:你把衣服丢到洗衣机洗,然后会客厅做其他事情,定时去阳台看洗衣机是不是洗完了,洗好后再去晾衣服(等待期间你可以做其他事情)
  • 异步非阻塞:你把衣服丢到洗衣机洗,然后会客厅做其他事情,洗衣机洗好后会自动去晾衣服,晾完成后放个音乐告诉你洗好衣服并晾好了

下面讲解几个网络模型

BIO:同步阻塞模型

网络I/O模型 - 图1

进程得一直等待数据完成才能进行下一步工作。(等衣服洗完)

基础NIO:同步非阻塞模型

网络I/O模型 - 图2

进程可以去干别的事情,但是得不断反复检查数据是否准备完全。(去看电视但是得反复检查衣服洗完没有)

I/O多路复用

网络I/O模型 - 图3

跟上面的NIO差不多,但是多路复用不再是一对一的关系,而是可以利用一个线程检测多个线程情况,减少线程的开销。后续会再详细说明多路复用

信号驱动

网络I/O模型 - 图4

首先要允许接口进行信号驱动I/O,然后安装一个信号处理函数,线程继续运行并不阻塞。当数据准备好时,线程会收到一个SIGIO信号,可以在信号处理函数中调用I/O操作函数处理数据,这个用得比较少,我也不是很了解

Ok,经过上面的上面的讲解已经对同步是否阻塞已经有了认识,下面再讲讲同异步,其实上面的模型在后续对数据处理时都是阻塞的,对应上面例子就是不管你是否盯着洗衣机,最后都得你自己确认。而最后由洗衣机提示,就是异步I/O模型了

异步I/O

网络I/O模型 - 图5

当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者的输入输出操作。

总结

  • IO操作分为两步

发起IO请求,等待数据准备(Waiting for the data to be ready)

实际的IO操作,将数据从内核拷贝到进程中(Copying the data from the kernel to the process)

  • 前四种IO模型都是同步IO操作,区别在于第一阶段,而他们的第二阶段是一样的:在数据从内核复制到应用缓冲区期间(用户空间),进程阻塞于recvfrom调用或者select()函数。 相反,异步I/O模型在这两个阶段都要处理。
  • 阻塞IO和非阻塞IO的区别在于第一步,发起IO请求是否会被阻塞,如果阻塞直到完成那么就是传统的阻塞IO,如果不阻塞,那么就是非阻塞IO。同步IO和异步IO的区别就在于第二个步骤是否阻塞,如果实际的IO读写阻塞请求进程,那么就是同步IO,因此阻塞IO、非阻塞IO、IO复用、信号驱动IO都是同步IO,如果不阻塞,而是操作系统帮你做完IO操作再将结果返回给你,那么就是异步IO。

阻塞非阻塞说的是线程的状态

同步和异步说的是消息的通知机制

同步需要主动读写数据,异步是不需要主动读写数据

同步IO和异步IO是针对用户应用程序和内核的交互

补充

一些别人的看法

https://www.zhihu.com/question/19732473/answer/117012135

网络I/O模型 - 图6

然后:

https://blog.csdn.net/weixin_34332905/article/details/92850983?utm_medium=distribute.pc_relevant.none-task-blog-2~default~OPENSEARCH~default-1.baidujs&dist_request_id=1329187.26082.16179885380610395&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~OPENSEARCH~default-1.baidujs

整理的也很详细