谁能解释一下epoll,libevent,zeroMQ的区别
2016-04-11
展开全部
epoll跟select都能提供多路I/O复用的解决方案。在现在的Linux内核里有都能够支持,其中epoll是Linux所特有,而select则应该是POSIX所规定,一般操作系统均有实现。
网上现在关于这两者不同的介绍已经到处都是了。我这里滑卜简也不能多说出什么东西,只是记录下我看了实现代码之后的一些总结。
两者的使用场景一般是通过一个入口能够同时监控多路I/O。一般使用的接口,
epool就是
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
select为:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
通过上述两个函数能够将调用线程阻塞,线程变为可执行条件有两种情况:
无任何事件发生,超时时间已过
在所控制的I/O有事件到来
epoll_wait函数中看不到相关的监控信息,因为是通过epoll_ctl已经加入,而select之间在函数调用中由(fd_set *readfds, fd_set *writefds, fd_set *exceptfds)传入弊没。epoll_wait饭互结果通过events返回,而select的传入参数也是传出参数。两者传出参数均表示发生事件的对应I/O标识。
两种方式的区别主要体现在以下几个方面:
select所能控制的I/O数有限,这主要是因为fd_set数据结构是一个有大小的,相当与一个定长所数组。
select每次都需要重新设置所要监控的fd_set(因为调用之后会改变其内信裤容),这增加了程序开销。
select的性能要比epoll差,具体原因会在后续内容中详细说明。
嗯,说道这个为什么select要差,那就要从这个select API说起了。这个传进去一个数组,内部实现也不知道那个有哪个没有,所以要遍历一遍。假设说我只监控一个文件描述符,但是他是1000。那么select需要遍历前999个之后再来poll这个1000的文件描述符,而epoll则不需要,因为在之前epoll_ctl的调用过程中,已经维护了一个队列,所以直接等待事件到来就可以了。
Linux中select此段相关代码为:
/* 遍历所有传入的fd_set */
for (i = 0; i < n; ++rinp, ++routp, ++rexp) {
unsigned long in, out, ex, all_bits, bit = 1, mask, j;
unsigned long res_in = 0, res_out = 0, res_ex = 0;
const struct file_operations *f_op = NULL;
struct file *file = NULL;
in = *inp++; out = *outp++; ex = *exp++;
all_bits = in | out | ex;
/* 此处跳无需监控的fd, 白白的浪费时间啊…… */
if (all_bits == 0) {
i += __NFDBITS;
continue;
}
/* 后续进行一些相关操作 */
}
而epoll则无需进行此类操作,直接检测内部维护的一个就绪队列,如果队列有内容,说明有I/O就绪,那么直接赋值返回内容,成功返回,如果没有成功,那么睡眠,等待就绪队列非空。
通过这个两者的比较,其实两者的差距啊,大部分是因为这个API设计所决定的,select就设计成这样一个API,内部再怎么优化也只能是这么个烂样子,而epoll这样维护与等待分离,灵活多变,最后也就带来了相对的高性能,以及可扩展性。
网上现在关于这两者不同的介绍已经到处都是了。我这里滑卜简也不能多说出什么东西,只是记录下我看了实现代码之后的一些总结。
两者的使用场景一般是通过一个入口能够同时监控多路I/O。一般使用的接口,
epool就是
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
select为:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
通过上述两个函数能够将调用线程阻塞,线程变为可执行条件有两种情况:
无任何事件发生,超时时间已过
在所控制的I/O有事件到来
epoll_wait函数中看不到相关的监控信息,因为是通过epoll_ctl已经加入,而select之间在函数调用中由(fd_set *readfds, fd_set *writefds, fd_set *exceptfds)传入弊没。epoll_wait饭互结果通过events返回,而select的传入参数也是传出参数。两者传出参数均表示发生事件的对应I/O标识。
两种方式的区别主要体现在以下几个方面:
select所能控制的I/O数有限,这主要是因为fd_set数据结构是一个有大小的,相当与一个定长所数组。
select每次都需要重新设置所要监控的fd_set(因为调用之后会改变其内信裤容),这增加了程序开销。
select的性能要比epoll差,具体原因会在后续内容中详细说明。
嗯,说道这个为什么select要差,那就要从这个select API说起了。这个传进去一个数组,内部实现也不知道那个有哪个没有,所以要遍历一遍。假设说我只监控一个文件描述符,但是他是1000。那么select需要遍历前999个之后再来poll这个1000的文件描述符,而epoll则不需要,因为在之前epoll_ctl的调用过程中,已经维护了一个队列,所以直接等待事件到来就可以了。
Linux中select此段相关代码为:
/* 遍历所有传入的fd_set */
for (i = 0; i < n; ++rinp, ++routp, ++rexp) {
unsigned long in, out, ex, all_bits, bit = 1, mask, j;
unsigned long res_in = 0, res_out = 0, res_ex = 0;
const struct file_operations *f_op = NULL;
struct file *file = NULL;
in = *inp++; out = *outp++; ex = *exp++;
all_bits = in | out | ex;
/* 此处跳无需监控的fd, 白白的浪费时间啊…… */
if (all_bits == 0) {
i += __NFDBITS;
continue;
}
/* 后续进行一些相关操作 */
}
而epoll则无需进行此类操作,直接检测内部维护的一个就绪队列,如果队列有内容,说明有I/O就绪,那么直接赋值返回内容,成功返回,如果没有成功,那么睡眠,等待就绪队列非空。
通过这个两者的比较,其实两者的差距啊,大部分是因为这个API设计所决定的,select就设计成这样一个API,内部再怎么优化也只能是这么个烂样子,而epoll这样维护与等待分离,灵活多变,最后也就带来了相对的高性能,以及可扩展性。
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
名片
2024-10-28 广告
2024-10-28 广告
作为优菁科技(上海)有限公司的一员,Altair HyperWorks是我们重点代理的CAE软件套件。该软件以其全面的仿真能力、丰富的建模工具和高效的优化设计功能著称,广泛应用于汽车、航空航天、能源及电子等行业。HyperWorks通过集成...
点击进入详情页
本回答由名片提供
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询