Treasure / I/O

Created Mon, 25 Feb 2019 00:00:00 +0000
1192 Words

前言

  • 数据的读取分为:

    1. 等待数据准备

    2. 等待内核拷贝至用户空间

  • 基本模型矩阵

    阻塞 非阻塞
    同步 Read/Write Read\Write(O_NONBLOCK)
    异步 I/O multiplexing(select/poll) AIO

同步阻塞I/O

此时用户阻塞等待内核完成。

同步阻塞IO


同步非阻塞I/O

此时用户进程每过一段时间询问内核操作是否完成,若完成则开始复制,感官上用户进程没有阻塞,可以称之为伪异步,但本质还是同步。

同步阻塞IO


I/O多路复用

I/O复用 有时又被称为 事件驱动I/O, 它的最大优势在于,我们可以将感兴趣的多个I/O事件(更精确的说,应该是 I/O 所对应的文件描述符)注册到 select/poll/epoll/kqueue 之中某一个系统调用上(很多时候,这些系统调用又被称为多路复用器。假设此时我们选择了 select() )。此后,调用进程会阻塞在 select() 系统调用之上(而不是阻塞在真正的 I/O 系统调用(如 read(), write() 等)上)。select() 会负责监视所有已注册的 I/O 事件,一旦有任意一个事件的数据准备好,那么 select() 会立即返回,此时我们的用户进程便能够进行数据的复制操作。

IO复用

selectpollepollkqueue

  1. select

    说的通俗一点就是各个客户端连接的文件描述符也就是套接字,都被放到了一个集合中,调用 select 函数之后会一直监视这些文件描述符中有哪些可读,如果有可读的描述符那么我们的工作进程就去读取资源,仅返回触发事件,不返回事件id,最多只能监测1024个连接,线程不安全

  2. poll

    pollselect 的实现非常类似,本质上的区别就是存放 fd 集合的数据结构不一样。select 在一个进程内可以维持最多 1024 个连接,poll 在此基础上做了加强,可以维持任意数量的连接。

  3. epoll

    epoll 是基于内核的反射机制,在有活跃的 socket 时,系统会调用我们提前设置的回调函数。而 pollselect 都是遍历。在大多数客户端都很活跃的情况下,系统会把所有的回调函数都唤醒,所以会导致负载较高。既然要处理这么多的连接,那倒不如 select 遍历简单有效。


信号驱动I/O

在这种模型下,我们首先开启套接字的信号驱动式I/O功能,并通过sigaction系统调用安装一个信号处理函数。该系统调用将立即返回,我们的进程继续工作,也就是说他没有被阻塞。当数据报准备好读取时,内核就为该进程产生一个SIGIO信号。我们随后就可以在信号处理函数中调用read读取数据报,并通知主循环数据已经准备好待处理,也可以立即通知主循环,让它读取数据报。此时在收到内核完成信号之前是非阻塞的,但是内核复制数据时会发生阻塞,所以此模型也是一个伪异步

信号IO


异步非阻塞I/O

Windows的IOCP模型

异步非阻塞 /O模型 是一种处理与 I/O 重叠进行的模型。读请求会立即返回,说明 read 请求已经成功发起了。在后台完成读操作时,应用程序然后会执行其他处理操作。当 read 的响应到达时,就会产生一个信号或执行一个基于线程的回调函数来完成这次 I/O 处理过程。本质上阻塞是用户 I/O 线程,主线程是非阻塞的,所以此模型是真异步

异步非阻塞IO

仅unix支持

几种I/O模型的比较

判断是否是真正异步的方式是,内核完成通知之后是否是主线程处理,还是I/O线程处理。

IO模型的比较

ReactorProactor

还没写