https://blog.csdn.net/ocean_fan/article/details/79622956
(主要的延迟等待分为等待IO事件发生和执行IO读写两个部分,如果是内核来做就是异步)
- 阻塞IO模型:(read/write)
最传统,读写过程中堵塞直到完成。如果中间延迟很大,就一直等着,直到数据到来。

- 非阻塞IO模型:(reas/write设置O_NONBLOCK参数)
- 第一阶段不阻塞(用户进程询问内核,会立即得到回应,不阻塞 ),第二阶段会阻塞(要等着内核空间拷贝数据到用户空间并返回)。
用户轮训,迅速返回结果。

- 多路复用IO模型:(select,poll,epoll,Java的NIO)
- 第一阶段会阻塞在 selector 上,第二阶段拷贝数据也会阻塞。
比如Java的NIO,专门安排一个线程不断去轮训多个socket的状态,只有当socket真正有读写事件时,才真正调用实际的IO读写操作。如果换成多线程一对一阻塞IO服务socket,那么对于长连接的请求,线程资源就难以释放,如果请求多了就容易陷入瓶颈。
select的轮询是在内核里面完成的,不影响线程的工作。但是因为是单线程处理IO,如果某个事务占用了太多时间处理会导致后面的事务等待时间过长。

- 信号驱动模型
- 第一阶段不阻塞(注册信号会立刻返回),第二阶段阻塞(需要等待数据从内核空间拷贝到用户空间)。
当用户线程发起一个IO请求,会给对应的socket注册一个信号函数。然后用户线程会继续执行,当内核数据就位后便会在信号函数中调用IO读写操作来进行具体的请求操作。
一般用于UDP,对于TCP这种频繁响应的不太适用。

- 异步IO模型(C++的boost aio库,windows的IOCP)
- 两个阶段都不阻塞
以上的全是同步IO,在传输的时候堵塞,在等待的时候不阻塞。
异步IO的时候,发起read请求后立刻就去做别的事情。内核在接收到任务后立马返回不阻塞用户线程。然后内核会一直等待数据准备完成,然后将数据拷贝给用户线程,拷贝完成后会给用户线程一个信号。当线程接收到这个信号的时候,说明IO已经完成,可以直接去用数据了。
IO的两个阶段都不阻塞,不需要用户自己调用IO函数进行读写(这一步导致很多模型退化为同步模型)。JAVA中提供了Asynchronous IO,简称AIO。

网友评论