常用的I/O模型

目录

概念区分

同步/异步

阻塞和非阻塞

常见I/O模型

同步阻塞I/O

同步非阻塞

I/O多路复用

异步I/O


参考:https://www.cnblogs.com/myJavaEE/p/6721127.html

http://www.cnblogs.com/fanzhidongyzby/p/4098546.html

概念区分

同步/异步

同步和异步是相对的。

描述的是用户线程与内核的交互方式:同步指用户线程发起I/O请求后需要等待或者沦胥内核I/O操作完成后才能继续执行;异步指用户线程发起I/O请求后仍继续执行,当内核I/O操作完成后会通知用户线程,或者调用用户线程注册的回调函数。

同步:前后两个任务,有严格的顺序一致性,按照顺序执行,执行完一个后再执行另一个,需要等待、协调运行

异步:对顺序的要求和依赖没那么强。多线程是实现异步的一种方式。

实际编程中,同步和异步体现在请求和响应交互中。

同步:发送请求,响应结果

异步:发送请求,后续将结果以通知或者回调的方式返回。

阻塞和非阻塞

阻塞和非阻塞是相对的。

描述的是用户线程调用内核I/O的操作方式。阻塞是I/O操作需要彻底完成后才返回到用户空间。非阻塞指的是I/O操作被调用后立即返回给用户一个状态值,无需等到I/O彻底完成。

常见I/O模型

同步阻塞I/O

最简单的I/O模型,用户线程在读写时被阻塞,不能做其他任何事情,对CPU利用不高。

{
    // read阻塞
    read(socket, buffer);
    // 处理buffer          
    process(buffer);
}

同步非阻塞

用户线程不断发起I/O请求,数据未达到时系统返回状态值,数据达到后才真正读取数据。

{
    // read非阻塞   
    while(read(socket, buffer) != SUCCESS);
    process(buffer);
}

用户线程每次I/O请求都可以立即返回,但为了拿到数据需要不断轮询,消耗了大量的CPU,一般很少使用这种模型。

I/O多路复用

建立在内核提供的阻塞函数select上。

用户先将需要进行I/O操作的socket添加到select中,然后等待阻塞函数select返回。当数据到达后,socket被激活,用户线程就能直接发起read请求。

数据达到内核后通知用户线程,用户线程负责从内核空间拷贝数据。

{
    // 注册
    select(socket);
    // 轮询
    while(true) {
        // 阻塞
        sockets = select();
        // 数据到达, 解除阻塞
        for(socket in sockets) {
            if(can_read(socket)) {
            // 数据已到达, 那么socket阻不阻塞无所谓
       read(socket, buffer);
            process(buffer);
            }
        }
    }
}

可以给select注册多个socket,然后不断调用select读取被激活的socket,实现在同一线程内同时处理多个I/O请求的效果。 

异步I/O

当用户线程接收到通知时,数据已经被操作系统从内核拷贝到用户指定的缓冲区内,用户线程可以直接使用。

猜你喜欢

转载自blog.csdn.net/u010918487/article/details/89513377