select、poll和epoll都是IO多路复用机制,可以监视多个文件描述符fd(每个fd关联了对应的socket),一旦某个fd有事件发生,就能够通知程序进行相应的IO操作。(select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。)
epoll是linux2.6以后Linux特有的实现机制,select则是一般OS都有的实现机制。
1、select
每次调用select方法,都要将整个fd数组从用户空间传入内核,然后在内核轮询该数组,判断是否某个fd发生了事件。
缺点:
①可监视的fd的最大数量有限制,32位默认1024个,64位默认2048个。
②轮询fd数组的效率比较低(epoll避免了轮询);
③每次调用select方法,都要把fd数组从用户空间拷贝到内核,开销大。
2、poll
poll和select本质上没有区别,不同点在于poll使用的是fd链表,不限制fd的最大数量。
3、epoll
epoll可以理解为event poll,是事件驱动的。epoll会把所有用户感兴趣的fd都注册到内核中,这些fd以红黑树的形式存储,并为每个fd绑定回调函数,一旦某个fd就绪,回调函数就会把它放入到一个就绪链表中。
这样一来,每次调用epoll_wait方法时(类似select的select方法),只需要查看就绪链表的数据即可,不用像select和poll那样把所有的fd从用户空间拷贝到内核。
当有新的fd到来时,直接插入到红黑树中即可。所以,epoll也没有fd的最大数量限制,因为是把所有的fd都保存在一个红黑树中的。
epoll解决select和poll存在的问题,即每次执行方法时大面积的拷贝、轮询遍历、fd最大数量限制。