Java顺序IO性能

许多应用程序将一系列事件记录到基于文件的存储中,以供以后使用。 从日志记录和审核,直到在事件源设计或其紧密相关的CQRS中保留事务重做日志,这都可以是任何东西。
Java具有多种方法,可以通过这些方法将文件顺序写入或重新读取。 本文探讨了其中一些机制,以了解其性能特征。 对于本文的范围,我将使用预分配的文件,因为我想关注性能。 不断扩展文件会带来很大的性能开销,并给应用程序增加抖动,从而导致高度可变的延迟。 “为什么预分配的文件性能更好?”,我听到您问。 好吧,在磁盘上,文件是由一系列包含数据的块/页面组成的。 首先,重要的是这些块是连续的,以提供快速的顺序访问。 其次,必须分配元数据来描述此文件在磁盘上并保存在文件系统中。 典型的大文件将分配许多“间接”块,以描述包含组成该元数据一部分的文件内容的数据块链。 我将其留给读者或以后的文章来练习,以探讨不预先分配数据文件对性能的影响。 如果您使用过数据库,则可能已经注意到它预先分配了所需的文件。
考试
我想尝试2种文件大小。 一个足够大,可以测试顺序访问,但可以轻松放入文件系统缓存中;另一个更大,可以使缓存子系统被迫退出页面,以便可以加载新页面。 对于这两种情况,我将分别使用400MB和8GB。 我还将遍历文件多次以显示预热和预热特性。
我将测试4种顺序写入和读取文件的方式:
  1. 使用页面大小的普通字节[]的RandomAccessFile 。
  2. 缓冲的FileInputStream和FileOutputStream 。
  3. 具有页面大小的ByteBuffer的NIO FileChannel 。
  4. 使用NIO和直接MappedByteBuffer映射文件的内存。
这些测试在具有8GB RAM的2.0Ghz Sandybridge CPU,具有ext4文件系统的Fedora Core 15 64位Linux上的Intel 320 SSD和Oracle JDK 1.6.0_30上运行。

编码

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;import static java.lang.Integer.MAX_VALUE;
import static java.lang.System.out;
import static java.nio.channels.FileChannel.MapMode.READ_ONLY;
import static java.nio.channels.FileChannel.MapMode.READ_WRITE;public final class TestSequentialIoPerf
{public static final int PAGE_SIZE = 1024 * 4;public static final long FILE_SIZE = PAGE_SIZE * 2000L * 1000L;public static final String FILE_NAME = "test.dat";public static final byte[] BLANK_PAGE = new byte[PAGE_SIZE];public static void main(final String[] arg) throws Exception{preallocateTestFile(FILE_NAME);for (final PerfTestCase testCase : testCases){for (int i = 0; i < 5; i++){System.gc();long writeDurationMs = testCase.test(PerfTestCase.Type.WRITE,FILE_NAME);System.gc();long readDurationMs = testCase.test(PerfTestCase.Type.READ,FILE_NAME);long bytesReadPerSec = (FILE_SIZE * 1000L) / readDurationMs;long bytesWrittenPerSec = (FILE_SIZE * 1000L) / writeDurationMs;out.format("%s\twrite=%,d\tread=%,d bytes/sec\n",testCase.getName(),bytesWrittenPerSec, bytesReadPerSec);}}deleteFile(FILE_NAME);}private static void preallocateTestFile(final String fileName)throws Exception{RandomAccessFile file = new RandomAccessFile(fileName, "rw");for (long i = 0; i < FILE_SIZE; i += PAGE_SIZE){file.write(BLANK_PAGE, 0, PAGE_SIZE);}file.close();}private static void deleteFile(final String testFileName) throws Exception{File file = new File(testFileName);if (!file.delete()){out.println("Failed to delete test file=" + testFileName);out.println("Windows does not allow mapped files to be deleted.");}}public abstract static class PerfTestCase{public enum Type { READ, WRITE }private final String name;private int checkSum;public PerfTestCase(final String name){this.name = name;}public String getName(){return name;}public long test(final Type type, final String fileName){long start = System.currentTimeMillis();try{switch (type){case WRITE:{checkSum = testWrite(fileName);break;}case READ:{final int checkSum = testRead(fileName);if (checkSum != this.checkSum){final String msg = getName() +" expected=" + this.checkSum +" got=" + checkSum;throw new IllegalStateException(msg);}break;}}}catch (Exception ex){ex.printStackTrace();}return System.currentTimeMillis() - start;}public abstract int testWrite(final String fileName) throws Exception;public abstract int testRead(final String fileName) throws Exception;}private static PerfTestCase[] testCases ={new PerfTestCase("RandomAccessFile"){public int testWrite(final String fileName) throws Exception{RandomAccessFile file = new RandomAccessFile(fileName, "rw");final byte[] buffer = new byte[PAGE_SIZE];int pos = 0;int checkSum = 0;for (long i = 0; i < FILE_SIZE; i++){byte b = (byte)i;checkSum += b;buffer[pos++] = b;if (PAGE_SIZE == pos){file.write(buffer, 0, PAGE_SIZE);pos = 0;}}file.close();return checkSum;}public int testRead(final String fileName) throws Exception{RandomAccessFile file = new RandomAccessFile(fileName, "r");final byte[] buffer = new byte[PAGE_SIZE];int checkSum = 0;int bytesRead;while (-1 != (bytesRead = file.read(buffer))){for (int i = 0; i < bytesRead; i++){checkSum += buffer[i];}}file.close();return checkSum;}},new PerfTestCase("BufferedStreamFile"){public int testWrite(final String fileName) throws Exception{int checkSum = 0;OutputStream out = new BufferedOutputStream(new FileOutputStream(fileName));for (long i = 0; i < FILE_SIZE; i++){byte b = (byte)i;checkSum += b;out.write(b);}out.close();return checkSum;}public int testRead(final String fileName) throws Exception{int checkSum = 0;InputStream in = new BufferedInputStream(new FileInputStream(fileName));int b;while (-1 != (b = in.read())){checkSum += (byte)b;}in.close();return checkSum;}},new PerfTestCase("BufferedChannelFile"){public int testWrite(final String fileName) throws Exception{FileChannel channel = new RandomAccessFile(fileName, "rw").getChannel();ByteBuffer buffer = ByteBuffer.allocate(PAGE_SIZE);int checkSum = 0;for (long i = 0; i < FILE_SIZE; i++){byte b = (byte)i;checkSum += b;buffer.put(b);if (!buffer.hasRemaining()){buffer.flip();channel.write(buffer);buffer.clear();}}channel.close();return checkSum;}public int testRead(final String fileName) throws Exception{FileChannel channel = new RandomAccessFile(fileName, "rw").getChannel();ByteBuffer buffer = ByteBuffer.allocate(PAGE_SIZE);int checkSum = 0;while (-1 != (channel.read(buffer))){buffer.flip();while (buffer.hasRemaining()){checkSum += buffer.get();}buffer.clear();}return checkSum;}},new PerfTestCase("MemoryMappedFile"){public int testWrite(final String fileName) throws Exception{FileChannel channel = new RandomAccessFile(fileName, "rw").getChannel();MappedByteBuffer buffer = channel.map(READ_WRITE, 0,Math.min(channel.size(), MAX_VALUE));int checkSum = 0;for (long i = 0; i < FILE_SIZE; i++){if (!buffer.hasRemaining()){buffer = channel.map(READ_WRITE, i,Math.min(channel.size() - i , MAX_VALUE));}byte b = (byte)i;checkSum += b;buffer.put(b);}channel.close();return checkSum;}public int testRead(final String fileName) throws Exception{FileChannel channel = new RandomAccessFile(fileName, "rw").getChannel();MappedByteBuffer buffer = channel.map(READ_ONLY, 0,Math.min(channel.size(), MAX_VALUE));int checkSum = 0;for (long i = 0; i < FILE_SIZE; i++){if (!buffer.hasRemaining()){buffer = channel.map(READ_WRITE, i,Math.min(channel.size() - i , MAX_VALUE));}checkSum += buffer.get();}channel.close();return checkSum;}},};
}

结果

400MB file
===========
RandomAccessFile write=294,041,636 read=1,494,890,510 bytes/sec

BufferedStreamFile写入= 98,178,331读取= 286,433,566字节/秒
BufferedStreamFile写入= 100,244,738读取= 288,857,545字节/秒
BufferedStreamFile写入= 82,948,562读取= 154,100,827字节/秒 BufferedStreamFile写入= 108,503,311读取= 153,869,271字节/秒 BufferedStreamFile写入= 113,055,478读取= 152,608,047字节/秒

BufferedChannelFile写入= 228,443,948读取= 356,173,913字节/秒
BufferedChannelFile写入= 265,629,053读取= 374,063,926字节/秒
BufferedChannelFile写= 223,825,136读= 1,539,849,624字节/秒BufferedChannelFile写= 232,992,036读= 1,539,849,624字节/秒BufferedChannelFile写= 212,779,220读= 1,534,082,397字节/秒 MemoryMappedFile写入= 300,955,180读取= 305,899,925字节/秒 MemoryMappedFile写入= 313,149,847读取= 310,538,286字节/秒 MemoryMappedFile写入= 326,374,501读取= 303,857,566字节/秒 MemoryMappedFile写入= 327,680,000读取= 304,535,315字节/秒 MemoryMappedFile写入= 326895450读取= 303632320字节/秒

8GB文件
============
RandomAccessFile写入= 167,402,321读取= 251,922,012字节/秒 RandomAccessFile写入= 193,934,802读取= 257,052,307字节/秒 RandomAccessFile写入= 192,948,159读取= 248,460,768字节/秒 RandomAccessFile写入= 191,814,180读取= 245,225,408字节/秒 RandomAccessFile写入= 190,635,762读取= 275,315,073字节/秒

BufferedStreamFile写入= 154,823,102读取= 248,355,313字节/秒
BufferedStreamFile写入= 152,083,913读取= 253,418,301字节/秒
BufferedStreamFile写入= 133,099,369读取= 146,056,197字节/秒 BufferedStreamFile写入= 131,065,708读取= 146,217,827字节/秒 BufferedStreamFile写入= 132694052读取= 148116004字节/秒

BufferedChannelFile写入= 186703740读取= 215075218字节/秒
BufferedChannelFile写入= 190,591,410读取= 211,030,680字节/秒BufferedChannelFile写入= 187,220,038读取= 223,087,606字节/秒
BufferedChannelFile写入= 191,585,397读取= 221,297,747字节/秒 BufferedChannelFile写入= 192,653,214读取= 211,789,038字节/秒

MemoryMappedFile写入= 123,023,322读取= 231,530,156字节/秒
MemoryMappedFile写入= 121,961,023读取= 230,403,600字节/秒
MemoryMappedFile写入= 123,317,778读取= 229,899,250字节/秒 MemoryMappedFile写入= 121,472,738读取= 231,739,745字节/秒 MemoryMappedFile写入= 120,362,615读取= 231,190,382字节/秒

分析

多年来,我一直是直接使用RandomAccessFile的忠实拥护者 ,因为它提供了控制和可预测的执行。 从性能的角度来看,我从来没有发现使用缓冲流会很有用,而且情况似乎仍然如此。
在最近的测试中,我发现使用NIO FileChannel和ByteBuffer的性能要好得多。 使用Java 7,此编程方法的灵活性已得到改善,可以使用SeekableByteChannel进行随机访问。
似乎在某些情况下,读取RandomAccessFile和NIO可以很好地使Memory Mapped文件赢得写操作。
我看到这些结果因平台而异。 文件系统,操作系统,存储设备和可用内存都会产生重大影响。 在某些情况下,我看到内存映射文件的性能明显优于其他文件,但这需要在您的平台上进行测试,因为您的行程可能会有所不同……
推送最大吞吐量时,应特别注意使用内存映射的大文件。 我经常发现操作系统可能由于虚拟内存子系统上的压力而变得无响应。
结论
从Java执行顺序文件IO的不同方法在性能上存在显着差异。 并非所有方法都遥遥相等。 对于大多数IO,我发现使用ByteBuffers和Channels是IO库中最优化的部分。 如果缓冲流是您的IO库的选择,那么值得进行分支并熟悉Channel和Buffer的实现,甚至可以使用旧的RandomAccessFile进行回退。
参考: Mechanical Sympathy博客上的JCG合作伙伴 Martin Thompson提供的Java顺序IO性能 。

翻译自: https://www.javacodegeeks.com/2012/07/java-sequential-io-performance.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/371801.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

text段,data段,bss段,堆和栈

.bss段和.data段的区别 text段,data段,bss段,堆和栈转载于:https://www.cnblogs.com/jingzhishen/p/6203107.html

[BZOJ3529][Sdoi2014]数表

[BZOJ3529][Sdoi2014]数表 试题描述 有一张Nm的数表&#xff0c;其第i行第j列&#xff08;1 < i < n&#xff0c;1 < j < m&#xff09;的数值为能同时整除i和j的所有自然数之和。给定a&#xff0c;计算数表中不大于a的数之和。输入 输入包含多组数据。输入的第一行…

ZK的实际应用:MVVM –表单绑定

这是我们从头开始构建ZK应用程序的第二集。 上一篇文章涉及使用MVVM将数据加载和呈现到表中。 在本文中&#xff0c;我们将向您介绍ZK MVVM的表单绑定。 目的 我们将构建一个“添加”功能&#xff0c;使我们能够将新条目保存到清单中。 单击“添加”时出现表格 单击“保存”…

群晖按装mysql_如何连接群晖里的MYSQL数据库

匿名用户1级2018-08-27 回答一、连接远程数据库&#xff1a;1、显示密码如&#xff1a;MySQL 连接远程数据库(192.168.5.116)&#xff0c;端口“3306”&#xff0c;用户名为“root”&#xff0c;密码“123456”C:/>mysql -h 192.168.5.116 -P 3306 -u root -p1234562、隐藏密…

ZK的实际应用:MVVM –以编程方式更新视图

在前两篇文章中&#xff0c;我们使用ZK的MVVM功能来&#xff1a; 将数据加载到表中 使用表单绑定保存数据 我们已经看到&#xff0c;用注解NotifyChange&#xff08;&#xff09;装饰方法时&#xff0c;在执行完成后&#xff0c;将向Binder通知VM属性的更改&#xff0c;以便B…

给你一个笑脸

今日冬至&#xff0c;愿你笑靥如初 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8" /> <title>Document</title> </head> <body> <canvas id"mycanvas" width"800px&qu…

mysql安装与配置的截图_windows下MySQL5.6版本安装及配置过程附有截图和详细说明...

随着MYSQL版本的更新以及电脑系统的变化&#xff0c;我们给大家整理了各种电脑环境下安装MYSQL的图解过程&#xff0c;希望我们整理的内容能够帮助到大家&#xff1a;mysql安装图解总结https://www.jb51.net/article/142398.htm编辑者&#xff1a;Vocabulary下面详细介绍5.6版本…

mysql 更新日的数据类型_[每日更新-MySQL基础]5.常用的数据类型-整数和字符串

1. 数据类型在学习PHP的时候我们已经讲过数据类型了&#xff0c;所谓数据类型就是数据的格式。每一种数据类型在计算机中存储的方式会有差异&#xff0c;占用的存储容量也有区别&#xff0c;所以选择合适的数据类型可以节约我们的存储成本&#xff0c;也方便我们的程序运行和…

Hello World with Spring 3 MVC

在2005年&#xff0c;我对Martin Fowler的这篇文章对Spring进行了介绍。从那时起&#xff0c;我就修改了许多IoC框架&#xff0c;包括Guice &#xff0c; PicoContainer &#xff0c; NanoContainer等。虽然我很喜欢与IoC一起工作&#xff0c;但我必须说Spring在过去的5年中&am…

ansible 安装

1、简介 ansible是新出现的自动化运维工具&#xff0c;基于Python开发&#xff0c;集合了众多运维工具&#xff08;puppet、cfengine、chef、func、fabric&#xff09;的优点&#xff0c;实现了批量系统配置、批量程序部署、批量运行命令等功能。ansible是基于模块工作的&#…

JS原型详解

参考的别人家的博客http://www.cnblogs.com/ljchow/archive/2010/06/08/1753526.html ###JS原型####JS原型&#xff0c;就是原型对象&#xff0c;简称原型。不仅构造函数有&#xff0c;普通函数也有* 普通函数&#xff1a;javascript function puTong(){ }; alert(puTong.proto…

c# mysql 插入 和 查询_C#对数据库的操作(增删改查)

1、【在web.config文件中配置】2、【连接字符串】private static readonly string StrCon ConfigurationManager.ConnectionStrings["sqlConnection"].ToString();3、【查询数据方法】/// /// 查询数据/// /// 查询语句/// 参数/// public static DataTable QueryDa…

利用docker在window7下安装TensorFlow

安装过程下碰了不少坑&#xff0c;记录一下安装过程&#xff0c;方便以后有需要时复用。 1、安装docker 下载最新版本的docker并且默认安装即可&#xff0c;安装后打开Docker Quickstart Terminal&#xff0c;初次进去需要一段时间。 下载网址&#xff1a;https://www.docker.c…

哈希长度扩展攻击

在这篇文章中&#xff0c;我将尽力避免夏季的低迷&#xff0c;而将重点放在比抱怨天气更有趣的事情上-哈希长度扩展攻击。 散列长度扩展攻击没什么复杂或复杂的&#xff0c;说实话&#xff0c;这只是关于如何使用散列函数。 正如我以前的一篇文章中所讨论的那样&#xff0c;哈希…

2017年07月03号课堂笔记

2017年07月03号 星期一 多云 空气质量&#xff1a;轻度污染~中度污染 内容&#xff1a;MySQL第四节课 in和not in&#xff1b;两个表的内连接&#xff1b;exists和not exsits的使用&#xff1b;all,any和some&#xff1b; 使用子查询的注意事项&#xff1b;sql优化&#xff08…

excel文件被写保护怎么解除_u盘被写保护怎么解除,看完你就知道了

在平常我们使用U盘存储资料过程中&#xff0c;有时会发现U盘出现无法正常读写的现象&#xff0c;具备表现为U盘被写保护&#xff0c;无法正常执行读写操作。对于小编给大家提供以下解决方法&#xff0c;希望对大家能有所帮助。对U盘执行重置操作01上网搜索并下载“USBOOT”程序…

新建MAVEN项目--pom.xml报错

使用集成了maven的Eclipse版本新建maven项目后&#xff0c;配置文件pom.xml会在project以及引用的xsd文件处出现错误&#xff08;第一、二行报错&#xff09; 其中一个报错例子&#xff1a; Multiple annotations found at this line:- Plugin execution not covered by lifecy…

OSGi案例研究:模块化vert.x

OSGi使Java代码可以清晰地划分为多个模块&#xff0c;这些模块称为捆绑软件 &#xff0c;可以访问由每个捆绑软件的类加载器控制的代码和资源。 OSGi 服务提供了一种附加的分离机制&#xff1a;接口的用户不需要依赖于实现类&#xff0c;工厂等。 以下案例研究旨在使OSGi捆绑包…

mysql一些常用操作_表的一些常用操作_MySQL

bitsCN.com-创建表(也就是创建表结构)&#xff1a;create table tbl_name(列结构&#xff0c;即有哪些属性)[表选项]; 如&#xff1a;班级的信息&#xff1a;(班级编号&#xff0c;开班日期)create table java_class(class_num varchar(10),date_start date);注&#xff1a;该表…

网站appache的ab命令压力测试性能

①&#xff1a;相关不错的博文链接&#xff1a;http://johnnyhg.iteye.com/blog/523818 ②&#xff1a;首先配置好对应的环境上去&#xff0c;有对应的命令 ③&#xff1a;压力测试的指令如下&#xff1a; 1. 最基本的关心两个选项 -c -n例&#xff1a; ./ab -c 100 -n 10000 &…