This action will force synchronization from 编程界的小学生/java-legendary, which will overwrite any changes that you have made since you forked the repository, and can not be recovered!!!
Synchronous operation will process in the background and will refresh the page when finishing processing. Please be patient.
[toc]
author:编程界的小学生
date:2021/03/03
buffer快,因为FileOutputStream的是每次witre()都会执行syscall调用内核写入pagecache,而BufferedOutputStream的write()则是每次都写入jvm的8kb大小的缓冲区,等8kb满了后再执行syscall调用系统内核写入pagecache,不会每次都进行系统调用。
BIO
同步阻塞IO。服务端当accept一个客户端请求后,在recv或send调用阻塞时,将无法继续accept其他请求,比如等上一个阻塞的accept的recv或send完才能继续处理下一个,也就是无法处理并发!也无法在阻塞下面处理读写请求,因为还在阻塞中,下面的读写程序走不了,解决方式是服务端可以采取多线程,当accept一个请求后,开启线程进行recv,这样就能完成并发处理,但若并发过大的话会造成多线程的频繁切换,也会造成很大的开销。
NIO
同步非阻塞IO。服务端当accept一个客户端请求后,不会阻塞住,而是会加入fds集合中,每次轮询一遍fds集合recv(非阻塞)数据,没有数据的话立即返回-1,完全非阻塞,所以可以同时接收多个accept请求,也可以在accept下面继续读写请求,因为accept不会阻塞。不用开辟新线程,自己单线程就能办。但是每次轮询所有fd(包括没有发生读写事件的fd)都会产生一次系统调用,会很浪费性能的。这时候就引入了IO多路复用技术。
服务端采取单线程通过select/poll/epoll系统调用函数获取fd列表,遍历有事件的fd进行accept/recv/send处理,简单来说IO多路复用就是将NIO的多次系统调用转换为一次系统调用,具体的轮询操作交给内核去处理,而不是每轮询一次就进行一次系统调用。
epoll模型。
poll主要引入了pollfd结构体,里面包含了一个revents字段,这个字段用来进行标记是否有数据用的,引入结构体主要解决了select的fd不能复用的问题。
解决了poll模型留下的最后两个问题,也就是解决了select模型的全部问题。
只有Linux支持epoll模型,windows不支持。
select | poll | epoll | |
---|---|---|---|
操作方式 | 遍历 | 遍历 | 回调 |
底层实现 | bitmap | 数组 | 红黑树 |
IO效率 | 每次都遍历fds逐个判断找标记的fd,O(n)时间复杂度 | 每次都遍历fds逐个判断结构体revents字段标记的fd,O(n)时间复杂度 | 事件通知的方式,每当fd就绪,系统注册回调函数就会被调用,将就绪fd发那个到list里。O(1)时间复杂度 |
最大连接数 | 1024 | 无上限 | 无上限 |
fd拷贝 | 每次调用select,都需要把fds从用户态拷贝到内核态 | 每次调用poll。都需要把fds从用户态拷贝到内核态 | fd首次调用epoll_ctl拷贝到内核并保存,之后每次调用epoll_wait无需再次拷贝 |
epoll有EPOLLLT和EPOLLET两种触发模式,LT是默认的模式水平触发,ET是边缘触发。边缘触发比水平触发效率更高。因为边缘触发不会让同一个文件描述符多次被处理,比如有些文件描述符已经不需要再读写了,但是在水平触发下每次都会返回,而边缘触发只会返回一次。
比如三个redis-cli,假设2个redis-cli写入命令
假如一个应用要从磁盘文件中读取内容并通过网络发出去,需要经历如下四个拷贝:
零拷贝方案
1、用户态直接I/O
不经过内核态,直接操作磁盘。
2、mmap
Redis持久化、RocketMQ写盘、NIO、Netty都是mmap方式。
mmap是什么?
memory mapping 内存映射,相当于给文件弄个虚拟映射,这个虚拟映射就相当于在用户空间开辟了一块内存,这块内存与文件是一一对应的。所以我们直接操作那块内存就相当于操作了那个文件,不需要先到内核再到文件的过程了。也就是避免了用户态内核态之间拷贝的过程。
普通IO
文件通道FileChannel:全双工、采用bytebuffer缓冲区
MMAP:把文件映射到用户空间的虚拟内存中,写入很小的情况下效率才高于FileChannel,java的实现MappedByteBuffer很麻烦。
调用Mmap进行内存映射后,OS只是建立虚拟内存地址至物理地址的映射表,而实际并没有加载任何文件至内存中。
未完待续~!目前没得时间来研究,工作中目前也用不到,暂且搁置哈~
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。