IO模式
对于一次IO访问(以read举例),数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。所以说,当一个read操作发生时,它会经历两个阶段:
等待数据准备 (Waiting for the data to be ready)
将数据从内核拷贝到进程中 (Copying the data from the kernel to the process)
正式因为这两个阶段,linux系统产生了下面五种网络模式的方案。
- 阻塞 I/O(blocking IO)
A同学用杯子装水,打开水龙头装满水然后离开。这一过程就可以看成是使用了阻塞IO模型,因为如果水龙头没有水,他也要等到有水并装满杯子才能离开去做别的事情。很显然,这种IO模型是同步的。 - 非阻塞 I/O(nonblocking IO)
B同学也用杯子装水,打开水龙头后发现没有水,它离开了,过一会他又拿着杯子来看看……在中间离开的这些时间里,B同学离开了装水现场(回到用户进程空间),可以做他自己的事情。 - I/O 多路复用( IO multiplexing)(select/poll/epoll)
这个时候C同学来装水,发现有一排水龙头,舍管阿姨告诉他这些水龙头都还没有水,等有水了告诉他。于是等啊等(select调用中),过了一会阿姨告诉他有水了,但不知道是哪个水龙头有水,自己看吧。于是C同学一个个打开,往杯子里装水(recv)。这里再顺便说说鼎鼎大名的epoll(高性能的代名词啊),epoll也属于IO复用模型,主要区别在于舍管阿姨会告诉C同学哪几个水龙头有水了,不需要一个个打开看(当然还有其它区别)。 - 信号驱动 I/O( signal driven IO)
D同学让舍管阿姨等有水的时候通知他(注册信号函数),没多久D同学得知有水了,跑去装水。是不是很像异步IO?很遗憾,它还是同步IO(省不了装水的时间啊)。 - 异步 I/O(asynchronous IO)
E同学让舍管阿姨将杯子装满水后通知他。整个过程E同学都可以做别的事情(没有recv),这才是真正的异步IO。
阻塞IO模型、非阻塞IO模型、IO复用模型(select/poll/epoll)、信号驱动IO模型都属于同步IO
同步的使用场景:
不使用异步的时候
同步的好处:
1、同步流程对结果处理通常更为简单,可以就近处理。
2、同步流程对结果的处理始终和前文保持在一个上下文内。
3、同步流程可以很容易捕获、处理异常。
4、同步流程是最天然的控制过程顺序执行的方式。
异步的使用场景:
1、不涉及共享资源,或对共享资源只读,即非互斥操作
2、没有时序上的严格关系
3、不需要原子操作,或可以通过其他方式控制原子性
4、常用于IO操作等耗时操作,因为比较影响客户体验和使用性能
5、不影响主线程逻辑
异步的好处:
1、异步流程可以立即给调用方返回初步的结果。
2、异步流程可以延迟给调用方最终的结果数据,在此期间可以做更多额外的工作,例如结果记录等等。
3、异步流程在执行的过程中,可以释放占用的线程等资源,避免阻塞,等到结果产生再重新获取线程处理。
4、异步流程可以等多次调用的结果出来后,再统一返回一次结果集合,提高响应效率。