I/O多路复用

同步和异步

所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。调用者等待处理结果。

例如:排队时,取完号后,过一会问一下到了没有。

异步的概念和同步相对。当一个异步过程调用发出后,调用者不会立刻得到结果。被调用者通知调用者处理结果。

例如:排队时,取完号之后,等着叫号。

以 Socket为例,当一个客户端通过调用 Connect函数发出一个连接请求后,调用者线程不用等待结果,可立刻继续向下运行。当连接真正建立起来以后,socket底层会发送一个消息通知该对象。

阻塞和非阻塞

阻塞调用是指调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回。

例如:排队时,一直等着,直到排到自己。

非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。

例如:排队时,边玩手机便排队。

区别和组合

同步与异步,重点在于消息通知的方式;阻塞与非阻塞,重点在于等消息时候的行为。可能的组合方式有以下几种 。

同步阻塞形式

效率是最低的。例子,排队时你专心排队,什么别的事都不做。 实际程序中,就是未对fd 设置O_NONBLOCK 标志位的read/write 操作。
imag

异步阻塞形式

排队时,等着被叫号,什么其他的时也干不了。异步操作可以被阻塞,比如说提前在前面有人在处理时先叫到你的号。 比如select 函数,假如传入的最后一个timeout 参数为NULL,那么如果所关注的事件没有一个被触发,程序就会一直阻塞在这个select 调用处。

同步非阻塞形式

排队时,可以打电话,一直需要看有没有排到自己。任务间来回切换,即轮询(polling)的方式,效率也比较低。read/write 操作,可以对fd设置O_NONBLOCK 标志位,这样就可以将同步操作变成非阻塞的了。

imag

同步非阻塞方式相比同步阻塞方式:
优点是能够在等待任务完成的时间里干其他活了(包括提交其他任务,也就是可以有多个任务在同时执行)。
缺点是任务完成的响应延迟增大了,因为每过一段时间才去轮询一次,而任务可能在两次轮询之间的任意时间完成。

异步非阻塞形式

排队时,专心打电话,排到时有人会通知到。
imag

I/O多路复用

所谓的I/O复用,就是多个I/O可以复用一个进程。
imag

早期的IO多路复用采用非阻塞的模式,当一个连接过来时,我们不阻塞住,这样一个进程可以同时处理多个连接了。但是进程需要一直轮训所有连接是否有事件需要处理,这样效率十分低下。
后来出现了select、poll,其原理是引入了一个代理,由代理去观察所有的连接,当有算时间触发时由代理通知进程处理,但是进程还是需要去找具体哪个连接有时间处理。select和poll减少了进程轮训所有连接的次数,节省了cpu时间。select和poll的区别是select只能观察1024个连接,poll可以观察无限个连接。

但同样select和poll有两个缺点:

  • 每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大
  • 同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大

后来又出现了epoll,epoll代理和select,poll类似,epoll通过以下两个方法解决以上问题:

  • 第一个缺点,epoll的解决方案在epoll_ctl函数中。每次注册新的事件到epoll句柄中时(在epoll_ctl中指定EPOLL_CTL_ADD),会把所有的fd拷贝进内核,用了mmap共享了用户和内核的部分空间,而不是在epoll_wait的时候重复拷贝。epoll保证了每个fd在整个过程中只会拷贝一次。
  • 第二个缺点,epoll的解决方案是基于事件驱动,不像select或poll一样每次都把current轮流加入fd对应的设备等待队列中,而只在epoll_ctl时把current挂一遍(这一遍必不可少)并为每个fd指定一个回调函数,当设备就绪,唤醒等待队列上的等待者时,就会调用这个回调函数,而这个回调函数会把就绪的fd加入一个就绪链表。epoll_wait的工作实际上就是在这个就绪链表中查看有没有就绪的fd。这样进程不用去轮训,大大节省了cpu时间。同时epoll 现在是线程安全的。

Epoll是非阻塞的,但不是异步的。实现非阻塞很简单。实现异步却很复杂,在《UNIX网络编程》中给出的5中I/O模型,只有最后一种是异步模型,其他的都是非异步的。
Linux没有实现异步IO(效率并不高),select,poll,Epoll都是一种I/O多路复用技术,但他们都是同步的I/O,都需要主动的去询问内核是否有事件发生,而不是事件发生时内核主动的去调用回调函数,所以不是异步的。

参考:
IO-同步,异步,阻塞,非阻塞
socket阻塞与非阻塞,同步与异步、I/O模型