select和epoll的区别

selectepoll的区别

当需要读两个以上的I/O的时候,如果使用阻塞式的I/O,那么可能长时间的阻塞在一个描述符上面,另

外的描述符虽然有数据但是不能读出来,这样实时性不能满足要求,大概的解决方案有以下几种:

1. 使用多进程或者多线程,但是这种方法会造成程序的复杂,而且对与进程与线程的创建维护也需要

很多的开销(Apache服务器是用的子进程的方式,优点可以隔离用户);

2. 用一个进程,但是使用非阻塞的I/O读取数据,当一个I/O不可读的时候立刻返回,检查下一个是否

可读,这种形式的循环为轮询(polling),这种方法比较浪费CPU时间,因为大多数时间是不可

读,但是仍花费时间不断反复执行read系统调用;

3. 异步I/O,当一个描述符准备好的时候用一个信号告诉进程,但是由于信号个数有限,多个描述符

时不适用;

4. 一种较好的方式为I/O多路复用,先构造一张有关描述符的列表(epoll中为队列),然后调用一个

函数,直到这些描述符中的一个准备好时才返回,返回时告诉进程哪些I/O就绪。selectepoll

两个机制都是多路I/O机制的解决方案,selectPOSIX标准中的,而epollLinux所特有的。

它们的区别主要有三点:

1. select的句柄数目受限,在linux/posix_types.h头文件有这样的声明: #define __FD_SETSIZE

1024 表示select最多同时监听1024fd。而epoll没有,它的限制是最大的打开文件句柄数目;

2. epoll的最大好处是不会随着FD的数目增长而降低效率,在selec中采用轮询处理,其中的数据结构

类似一个数组的数据结构,而epoll是维护一个队列,直接看队列是不是空就可以了。epoll只会对

活跃socket进行操作这是因为在内核实现中epoll是根据每个fd上面的callback函数实现的。那

么,只有活跃socket才会主动的去调用 callback函数(把这个句柄加入队列),其他idle状态

句柄则不会,在这点上,epoll实现了一个”AIO。但是如果绝大部分的I/O都是活跃的,每个I/O

端口使用率很高的话,epoll效率不一定比select高(可能是要维护队列复杂);

3. 使用mmap加速内核与用户空间的消息传递。无论是select,poll还是epoll都需要内核把FD消息通知

给用户空间,如何避免不必要的内存拷贝就很重要,在这点上,epoll是通过内核于用户空间

mmap同一块内存实现的。

WindowsAsynchronousSocketChannelImpl

Iocp.OverlappedChannel

UnixAsynchronousSocketChannelImpl

Port.PollableChannelNIOepoll

上文说到了selectepoll的区别,再总结一下Java NIOselectepoll

Linux2.6之后支持epoll

windows支持select而不支持epoll

不同系统下nio的实现是不一样的,包括Sunos linux windows

select的复杂度为O(N)

select有最大fd限制,默认为1024

修改sys/select.h可以改变selectfd数量限制

epoll的事件模型,无fd数量限制,复杂度O(1),不需要遍历fd

以下代码基于Java 8

下面看下在NIOSelectoropen方法:

这里使用了SelectorProvider去创建一个Selector,看下provider方法的实现:

看下 sun.nio.ch.DefaultSelectorProvider.create() 方法,该方法在不同的操作系统中的代码是

不同的,在windows中的实现如下:

Mac OS中的实现如下:

linux中的实现如下:

public static Selector open() throws IOException {

return SelectorProvider.provider().openSelector();

}

public static SelectorProvider provider() {

synchronized (lock) {

if (provider != null)

return provider;

return AccessController.doPrivileged(

new PrivilegedAction<SelectorProvider>() {

public SelectorProvider run() {

if (loadProviderFromProperty())

return provider;

if (loadProviderAsService())

return provider;

provider = sun.nio.ch.DefaultSelectorProvider.create();

return provider;

}

});

}

}

public static SelectorProvider create() {

return new WindowsSelectorProvider();

}

public static SelectorProvider create() {

return new KQueueSelectorProvider();

}我们看到create方法中是通过区分操作系统来返回不同的Provider的。其中SunOs就是Solaris返回的是

DevPollSelectorProvider,对于Linux,返回的ProvderEPollSelectorProvider,其余操作系统,返回

的是PollSelectorProvider

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

入伍击寇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值