现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

IO模型介绍

2018-03-04 22:26 工业·编程 ⁄ 共 1507字 ⁄ 字号 暂无评论

1、 同步阻塞IO(Blocking IO)

即传统的IO模型。当用户进程向系统发起read操作时,首先需要在内核中数据准备和内核态到用户进程的数据拷贝。当两个步骤都完成后,才会返回read结果状态,才能执行后续的数据处理操作。

{

    read(socket, buffer);

    process(buffer);

}

2、 同步非阻塞IO(Non-blocking IO)

默认创建的socket都是阻塞的,非阻塞IO要求socket被设置为NONBLOCK。当用户进程向系统发起read操作时,立即返回,但此时并没有读取到数据。用户线程需要不断地发起read请求,并根据返回的结果是否完成状态,来确定是否完成read操作。

while(read(socket, buffer) == SUCCESS) {

    process(buffer);

}

在非阻塞式IO中,用户进程需要不断的主动询问数据准备好了没有,需要消耗过多的CPU 资源。

3、 IO多路复用(IO Multiplexing)

经典的Reactor设计模式,有时也称为异步阻塞IO,Java中的Selector和Linux中的epoll都是这种模型。以下以select为例进行说明。使用select函数进行IO请求和同步阻塞模型没有太大的区别,甚至还多了添加监视socket,以及调用select函数的额外操作,效率更差。但是,使用select以后最大的优势是用户可以在一个线程内同时处理多个socket的IO请求。用户可以注册多个socket,然后不断地调用select读取被激活的socket,即可达到在同一个线程内同时处理多个IO请求的目的。而在同步阻塞模型中,必须通过多线程的方式才能达到这个目的。

{

    select(socket);

    while(1) {

        ready_sockets = select();

        for(socket in ready_sockets) {

            if(can_read(socket)) {

                read(socket, buffer);

                process(buffer);

            }

        }

    }

}

4、 异步IO(Asynchronous IO)

Proactor设计模式,也称为异步非阻塞IO。用户进程发起read操作之后,立刻就可以开始去做其它的事。而内核在接收到asynchronous read之后,内核会进行数据准备和数据拷贝至用户内存,当这两个步骤都完成后,内核会给用户进程发送一个signal,通知read操作完成。这一过程不会对用户进程产生任何block。

相比于IO多路复用模型,异步IO并不十分常用,不少高性能并发服务程序使用IO多路复用模型+多线程任务处理的架构基本可以满足需求。况且目前操作系统对异步IO的支持并非特别完善,更多的是采用IO多路复用模型模拟异步IO的方式(IO事件触发时不直接通知用户线程,而是将数据读写完毕后放到用户指定的缓冲区中)

在non-blocking IO中,虽然进程大部分时间都不会被block,但是它仍然要求进程去主动的check,并且当数据准备完成以后,也需要进程主动将数据拷贝到用户内存。I/O multiplexing中虽然在数据准备阶段和数据拷贝阶段会被block,由于其基于事件通知的,避免了持续check数据是否。而asynchronous IO则完全不同。它就像是用户进程将整个IO操作交给了内核去完成,然后等待信号通知,用户进程不需要检查IO操作的状态,也不需要主动的去拷贝数据。

 

给我留言

留言无头像?