关于IO

IO简介

The C10K problem提出后,不仅给web服务器的代码设计开发提供了思路,也给整个网络通信的架构提出了建议和意见,于是各种eventloop层出不穷(libevent/libev/libuv/redis的ae/nginx的event等等,这样的说法可能不正确,这些代码的出现应该是伴随着C10K问题完善的)。

《UNIX网络编程》将IO模型分为五类:阻塞式IO/非阻塞式IO/IO多路复用/信号驱动式IO/异步IO(参考:《Unix系统的IO模型》),而IO的多路分离及异步非阻塞这样的通信模型几乎集成在目前所有的高性能服务端程序框架中。

个人理解

下面谈谈我对他们的理解:

关于IO的多路分离

IO的多路分离器有select,poll,dev/poll,epoll,kqueue等,网络上已经有很多对他们的对比和解释,此处不再赘述了。

值得关注的是,从陈硕大牛的这篇《Linux 新增系统调用的启示》中可以发现linux kernel引入了timerfd,signalfd,eventfd后,带来的好处在于我不需要再自己维护一个timer结构(list或者rbtree)便可处理timeout事件了,不需要makepipe便可处理signal事件了,而eventfd不仅提供一种线程间通信方式,实际上也为用户级事件提供了接口(实际上nanomsg正是用它来处理task的)。这样我们在linux上实现一个eventloop要容易很多,通过接口创建对应事件的fd后加入到epoll池中即可,当然需要注意的是可能要设置最大打开句柄数(ulimit -n,默认的1024可能不一定够用)。

关于非阻塞

在创建文件描述符fd时,增加相应NONBLOCK标志(很多系统调用均支持额外的flags参数,比如:accept4,eventfd2,pipe2等,也可通过fcntl事后设置O_NONBLOCK),即为非阻塞了:

而在读写时,都需要对read或write包上一层while:

do {

read()/write()

} while(errno == EAGAIN ||errno == EWOULDBLOCK || errno == EINTR);

关于异步IO

目前应该是有两类异步IO的实现方式:

一种是线程池模拟(glibc的aio:http://www.ibm.com/developerworks/linux/library/l-async/ ;libev作者写的libeio:http://software.schmorp.de/pkg/libeio.html ;而libuv则是自己将线程池的实现集成到自己内部threadpool.c,然后将对文件系统的操作以及getaddrinfo()包裹于其上,实现了其文件操作及getaddrinfo()的异步化);

另一种则是linux在2.6.22版本后自带的native aio(nginx则是真正利用linux native aio(syscall方式)实现的异步IO;参考:http://www.pagefault.info/?p=76

参考资料

以下是几位大牛的文章,我觉得都挺不错的:

  1. Unix系统的IO模型
  2. Linux下异步IO(libaio)的使用以及性能
  3. nginx 0.8.x稳定版对linux aio的支持
  4. Linux 新增系统调用的启示

写在最后

这段时间懒了,本来计划写nanomsg源码阅读《三》的,也就是nanomsg的aio模块,然后写的过程中发现有许多的基础知识需要补一下,顺便读了些事件驱动程序的源码,简单的整理了一下,我会尽快aio的源码阅读的。

欢迎大家讨论补充,若有错误,还请指正!