JAVA NIO(五):如何在5秒内写入10G的文本数据
来源:互联网 发布:跨省网络诈骗多少立案 编辑:程序博客网 时间:2024/06/07 22:07
首先说本机的性能,采用AS SSD Benchmark进行评测,写入能力大约在422M每秒,计划连续写入文本数据,直到达到要求为止(5G数据与10G数据),测试环境如下:
1. FileOutputStream与BufferedWriter
原以为FileOutputStream的性能会很低,BufferedWriter会有一定的性能提升,但结果却让我大吃一惊,测试数据如下:
BufferedWrirter竟然还稍稍慢于FileOutputStream,并且FileOutputStream的性能如此惊人,已经完全达到了硬盘的性能巅峰,这说明JAVA的IO优化还是令人非常满意的,相关代码如下:
// FileOutputStream的写入方式类似,在此略static void writeBuffer(File file) throws IOException { FileOutputStream fos = new FileOutputStream(file); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos)); int i = 1000000; while(i > 0) { // word2048为字符串常量,刚好4800个字节 writer.write(word2048); i --; } writer.close(); fos.close();}
2. ByteBuffer与直接缓冲区
几乎所有的人都推荐,nio性能极佳,那真实的性能到底怎样?
从上面的数据可以看出,采用ByteBuffer后,性能约有10%的提升,但令人惊讶的,采不采用直接缓冲区竟然没有差异,这与理论推测又有显著差异(具体请参见《JAVA NIO》第45页),在这里还有一个可优化的地方,如何选择ByteBuffer的大小是决定写入速度的关键,相关代码如下:
FileOutputStream fos = new FileOutputStream(file);FileChannel fc = fos.getChannel();// 此数字可优化int times = 100;// word2048为字符串常量,刚好4800个字节byte[] datas = word2048.getBytes();ByteBuffer bbuf = ByteBuffer.allocate(4800 * times);int i = 10000;while(i > 0) { for(int j = 0; j < times; j++) { bbuf.put(datas); } bbuf.flip(); fc.write(bbuf); bbuf.clear(); i --;}
从这里来看,跟BIO相比,NIO性能提升并不明显。
3. FileChannel与文件空洞
在nio中,FileChannel可以决定文件的写入位置,这也是能产生文件空洞的主要方法,那么这样,产生大量的文件空洞,是否能加快文件的创建速度呢?
可以看出,写入速度主要还是受限与磁盘IO,即使少写数据,依旧不能提升速度,反而还有较大幅度的下降,相关代码如下:
FileOutputStream fos = new FileOutputStream(file);FileChannel fc = fos.getChannel();ByteBuffer bbuf = ByteBuffer.allocateDirect(1024);long value = 10 * 1024 * 1024;// 为什么不一步到位?直接将position设置10Gfor(int i = 1; i < 1025; i = i * 2) { bbuf.put((byte)1); bbuf.flip(); fc.position(i * value); fc.write(bbuf); bbuf.clear();}fc.close();fos.close();
在这里需要强调的一点是,文件大小的速度不能增长太快,否则必然出现“IllegalArgumentException”错误,这也是上述代码中需要划分多次循环的原因。
4. 惊人的MappedByteBuffer
早就听说直接内存映射提升IO性能惊人,那到底有多惊人呢?请看测试数据:
跟前面的最快的NIO方法相比,性能竟然提升了244%,写入速度竟然达到了1.8G每秒,这是怎么做到的?相关代码如下:
// 必须采用RandomAccessFile,并且是rw模式RandomAccessFile acf = new RandomAccessFile(file, "rw");FileChannel fc = acf.getChannel();byte[] bs = word2048.getBytes();int len = bs.length * 1000;long offset = 0;int i = 2000000;while(i > 0) { MappedByteBuffer mbuf = fc.map(FileChannel.MapMode.READ_WRITE, offset, len ); for(int j = 0; j < 1000; j ++) { mbuf.put(bs); } offset = offset + len; i = i - 1000;}fc.close();
当然,性能提升的代价也是很明显的,内存消耗至少增加了2G(直接内存,不是JAVA堆内存),而前面的方法内存消耗都很少,大多只在30M左右。
5. 其他的现象
- 同样的文件名,删除了再创建,速度又有10~20%的提升;
- 字符串转换为字节数组的速度极快,比直接写入字符串的速度更快,这也是BufferedWrirter比FileOutputStream慢的原因;
结论
直接内存映射、直接缓冲区都能提升IO写入的性能,背后的核心技术还是分页技术(请参加操作系统原理),如何组织分页的范围与写入的频次,是提升性能的关键,另外,写入对内存与CPU性能消耗都不高。
- JAVA NIO(五):如何在5秒内写入10G的文本数据
- Java如何读取和操作上G文本数据
- 异步ping的实现,如何在10秒内ping完20000个设备
- Java中如何将输入的信息写入文本中
- 在Java中如何读取用MATLAB的fwrite()函数写入文件的数据
- EMC颜开分析Dremel原理,如何在3秒内分析1PB数据
- JAVA NIO(六):读取10G的文件其实很容易
- 借助 Java 9 Jigsaw,如何在 60 秒内创建 JavaFX HelloWorld 程序?
- C++文本数据写入
- table control的search help是如何将数据写入内表的
- 用js向弹出的窗体内写入文本
- java读取大文本直接插入Mysql数据库,10万条数据4秒执行完
- linux之如何快速在文本里面写入内容
- java写入文本到文件中如何调用系统的换行
- java:24G文件写入所要时间23.9分,读取只有67秒(1G内存测试)
- Java NIO读/写入文件
- Java写入文本
- java文本读取写入
- UNIX环境高级编程笔记之线程
- HDU 6115 Factory(在线倍增LCA)
- 18. 4Sum
- 搭建lnmp环境(mysql5.7-yum)
- B. Minimum number of steps
- JAVA NIO(五):如何在5秒内写入10G的文本数据
- C++编译指令#pragma pack的配对使用
- 搭建lnmp环境(php7.1.8-源码)
- UNIX环境高级编程笔记之进程
- C#不同窗体的切换效果及单选控件属性变化
- 搭建lnmp环境(nginx1.9.15-源码)
- 设计模式-(2)工厂方法
- 【GDOI2018模拟9.16】幽雅的绽放吧,墨染之樱
- 若干次模拟赛的总结