我是靠谱客的博主 细心电源,最近开发中收集的这篇文章主要介绍Linux 中系统调用 select,poll,epoll 优缺点总结selectpollepoll,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
select
示例
函数原型
typedef struct {
unsigned long fds_bits [__FDSET_LONGS];
} fd_set;
int select(int ndfs, fd_set *readfds, fd_set *writefds, fd_set *exceptefds, struct timeval *timeout);
使用示例:
fd_set readfds,allfds;
FD_ZERO(&allfds);
FD_SET(1, &allfds);
...
for ( ; ; ) {
readfds = allfds;
nready = select(maxfds + 1, &readfds, NULL, NULL, NULL);
if (nready > 0) {
for (int i = 0; i <= maxfds; ++i) {
if (FD_ISSET(i, &readfds)) {
...
}
}
}
}
缺点:
从上面可以看出:
- 无论关注多少个描述符,都要使用固定大小的 fd_set,数据太小时存在空间浪费,但是数据太多时,又存在最大描述符个数的限制,一般描述符总数个数为 1024。
- 每次函数调用从用户空间到内核空间,结果返回从内核空间到用户空间都要传递整个 fd_set,而不管有多少个感兴趣的描述符及激活的描述符。
- 结果返回后,还要遍历范围内所有的描述符以确定哪些描述符可用。
- 因为 fd_set 同时也是结果保存的地方,因此需要每次初始化感兴趣的描述符。
- 内核中的实现方式是轮询所有的描述符。
poll
示例
函数原型:
struct pollfd {
int fd;
short events;
short revents;
}
int poll(struct pollfd fds[], nfds_t nfds, int timeout);
使用示例:
struct pollfd client[OPEN_MAX];
client[0].fd = listenfd;
client[0].events = POLLRDNORM;
...
for ( ; ; ) {
nready = poll(client, maxi, INFTIM);
if (nready > 0) {
for (int i=0; i < maxi; ++i) {
if (client[i].events & POLLRDNORM) {
...
}
}
}
}
优点:
相比于 select 的改进:
- 没有最大描述符个数的限制。
- 只用传递感兴趣的描述符,有利于提高在内核中轮询的效率。
- 不需要每次初始化感兴趣的描述符。
缺点:
- 每次函数调用,依旧需要从用户态和内核态之间传递
所有描述符
。 - 函数返回后,依旧需要遍历
所有描述符
,以确定哪些描述符可用。 - 内核中依旧需要轮询
所有描述符
。
epoll
示例
函数原型:
struct epoll_event {
uint32_t events;
epoll_data_t data;
}
int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *ev);
int epoll_wait(int epfd, struct epoll_event *evlist, int maxevents; int timeout);
使用示例:
#define MAX_EVENTS 5
struct epoll_event ev;
struct epoll_event evlist[MAX_EVENTS]; # 每次函数调用返回的结果,设置一个较小数目
int epfd = epoll_create(1);
if (epfd == -1)
error();
ev.data.fd = fd;
ev.events = EPOLLIN;
if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, ev) == -1)
error();
for ( ; ; ) {
nready = epoll_wait(epfd, evlist, MAXEVENTS, -1);
if (nready > 0) {
for (int i = 0; i < nready; ++i) {
if (evlist[i].events & EPOLLIN) {
...
}
}
}
}
优点
- 感兴趣的描述符只用通过 epoll_ctl 添加一次,不再需要每次函数调用中传递。
- 返回的结果规模更小,里面只包含已经激活的描述符,一方面减轻从内核态返回数据的负担,另一方面不需要进行大规模遍历。
- epoll_wait 内核中使用回调函数替代轮询,提高效率。
- 通过设置 EPOLLONESHOT,可以实现水平触发和边缘触发的切换。
最后
以上就是细心电源为你收集整理的Linux 中系统调用 select,poll,epoll 优缺点总结selectpollepoll的全部内容,希望文章能够帮你解决Linux 中系统调用 select,poll,epoll 优缺点总结selectpollepoll所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复