Java nio 本质上select()模型,可以检查/jre/bin/nio.dll得知。至于Java服务器为什么效率还不错,可能是因为设计的比较好。
底层:I/O多路复用技术。
1、每个连接对应一个描述。select模型受限于 FD_SETSIZE即进程最大打开的描述符数linux2.6.35为1024,实际上linux每个进程所能打开描数字的个数仅受限于内存大小,然而在设计select的系统调用时,却是参考FD_SETSIZE的值。可通过重新编译内核更改此值,但不能根治此问题,对于百万级的用户连接请求 即便增加相应 进程数, 仍显得杯水车薪呀。
2、select每次都会扫描一个文件描述符的集合,这个集合的大小是作为select第一个参数传入的值。但是每个进程所能打开文件描述符若是增加了 ,扫描的效率也将减小。
3、内核到用户空间,采用内存复制传递文件描述上发生的信息。
1)无文件描述字大小限制仅与内存大小相关
2)epoll返回时已经明确的知道哪个socket fd发生了什么事件,不用像select那样再一个个比对。
3)内核到用户空间采用共享内存方式,传递消息。
4)epoll的最大好处是不会随着FD的数目增长而降低效率,在selec中采用轮询处理,其中的数据结构类似一个数组的数据结构,而epoll是维护一个队列,直接看队列是不是空就可以了。epoll只会对"活跃"的socket进行操作---这是因为在内核实现中epoll是根据每个fd上面的callback函数实现的。那么,只有"活跃"的socket才会主动的去调用 callback函数(把这个句柄加入队列),其他idle状态句柄则不会,在这点上,epoll实现了一个"伪"AIO。但是如果绝大部分的I/O都是“活跃的”,每个I/O端口使用率很高的话,epoll效率不一定比select高(可能是要维护队列复杂)。
5)使用mmap加速内核与用户空间的消息传递。无论是select,poll还是epoll都需要内核把FD消息通知给用户空间,如何避免不必要的内存拷贝就很重要,在这点上,epoll是通过内核于用户空间mmap同一块内存实现的。
综上所述,select和epoll对比如下表所示
select |
epoll |
|
性能 |
随着连接数增加,急剧下降。处理成千上万并发连接数时,性能很差。 |
随着连接数增加,性能基本上没有下降。处理成千上万并发连接时,性能很好。 |
连接数 |
连接数有限制,处理的最大连接数不超过1024。如果要处理超过1024个连接数,则需要修改FD_SETSIZE宏,并重新编译 。 |
连接数无限制。 |
内在处理机制 |
线性轮询 |
回调callback |
开发复杂性 |
低 |
中 |
消息传递 |
|
epoll通过内核与用户空间通过共享内存进行消息传递 |
原文:https://www.cnblogs.com/Maarten/p/15313622.html