Linux IO多路复用分析(Select、Poll和Epoll)

前段时间被迫把一坨没人维护代码中的Select机制换成了Epoll,借此机会梳理一下Select、Poll和Epoll的原理。

I/O多路复用:

I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。但select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。

Select:

函数原型和使用:

#include <sys/select.h>
#include <sys/time.h>

int select(int maxfdp1,fd_set *readset,fd_set *writeset,fd_set *exceptset,const struct timeval *timeout)

void FD_ZERO(fd_set *fdset);//清空集合
void FD_SET(int fd, fd_set *fdset);//将一个给定的文件描述符加入集合之中
void FD_CLR(int fd, fd_set *fdset);//将一个给定的文件描述符从集合中删除
int FD_ISSET(int fd, fd_set *fdset);// 检查集合中指定的文件描述符是否可以读写 

缺点:

  1. 每次调用select,都需要把fd集合从用户态拷贝到内核态,也需要在内核遍历传递进来的所有fd,开销过大
  2. select支持的文件描述符数量过小,默认是1024,且调大需要重新编译系统内核

Poll:

函数原型和使用:

# include <poll.h>

int poll ( struct pollfd * fds, unsigned int nfds, int timeout);

/*Poll结构体*/
struct pollfd {
int fd;/* 文件描述符 */
short events;/* 等待的事件 */
short revents;/* 实际发生了的事件 */
};

缺点:

  • 只解决了select描述符上限的问题,没解决效率问题。

Epoll:

epoll是在2.6内核中提出的,是之前的select和poll的增强版本。相对于select和poll来说,epoll更加灵活,没有描述符限制。epoll使用一个文件描述符管理多个描述符,将用户关系的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间的copy只需一次。

函数原型和使用:

#include <sys/epoll.h>

int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

struct epoll_event {
  __uint32_t events;  /* Epoll events */
  epoll_data_t data;  /* User data variable */
};

缺点:

  • 使用较为复杂

简单的总结:

对比 Select Poll Epoll
机制 轮询 轮询 通知
默认FD上限 1024 无上限 无上限
效率

参考资料:

https://www.cnblogs.com/anker/p/3265058.html
https://blog.csdn.net/qq_39612543/article/details/121963681

发表回复

您的电子邮箱地址不会被公开。