RandomAccessFile writeInt(int i) 与 write(byte[] b) - 性能
RandomAccessFile writeInt(int i) vs write(byte[] b) - performance
我今天遇到了一件关于 RandomAccessFile
的有趣事情。
我注意到使用 RandomAccessFile
的 writeInt(int i)
方法比使用 RandomAccessFile
的 write(byte[] b)
方法慢得多,我首先将 int 值转换为 byte [4] 数组。
我正在使用此代码进行转换
private static byte[] intToByte(int i)
{
byte[] result = new byte[4];
result[0] = (byte) (i >> 24);
result[1] = (byte) (i >> 16);
result[2] = (byte) (i >> 8);
result[3] = (byte) (i);
return result;
}
差异非常显着,有利于write(byte[] b)
。
用 JDK 8:
在我的笔记本电脑上写 100 万 int
s
- 通过
writeInt(int i)
方法花费了~9秒
- 通过
write(byte[] b)
花费了 ~2.3 秒
我在另一个环境中得到了类似的结果,我使用的是 JDK 7 和一台完全不同的机器。
writeInt(int i) 方法委托给本机 write0(int b)
方法,write(byte[] b)
委托给本机 writeBytes
.
当我进行分析时,我注意到大部分执行时间都花在了 writeInt
方法上。
有谁知道为什么我看到这么大的差异?似乎 writeInt
效率较低。
不打算详细说明我所做的更改,但您的测试有一点缺陷。我冒昧地对它们进行了一些更新,运行 也进行了一些测试:
@BenchmarkMode(value = { Mode.AverageTime })
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Warmup(iterations = 2, time = 2, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 2, time = 2, timeUnit = TimeUnit.SECONDS)
public class RandomAccessWriteFileTest {
public static void main(String[] args) throws Exception {
Options opt = new OptionsBuilder().include(RandomAccessWriteFileTest.class.getSimpleName())
.jvmArgs("-ea")
.shouldFailOnError(true)
.build();
new Runner(opt).run();
}
@Benchmark()
@Fork(1)
public long benchamrkWriteDirectInt(BenchmarkPlainIntSetup setupTest) {
try {
setupTest.raf.writeInt(6969);
return setupTest.raf.length();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Benchmark()
@Fork(1)
public long benchamrkWriteConvertedInt(BenchmarkConvertedIntSetup setupTest) {
try {
setupTest.raf.write(intToBytes(6969));
return setupTest.raf.length();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static byte[] intToBytes(int i) {
byte[] result = new byte[4];
result[0] = (byte) (i >> 24);
result[1] = (byte) (i >> 16);
result[2] = (byte) (i >> 8);
result[3] = (byte) i;
return result;
}
@State(Scope.Thread)
static public class BenchmarkConvertedIntSetup {
public RandomAccessFile raf;
public File f;
@Setup(Level.Iteration)
public void setUp() {
try {
f = new File("jmhDirectIntBenchamrk.ser" + ThreadLocalRandom.current().nextInt());
raf = new RandomAccessFile(f, "rw");
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
@TearDown(Level.Iteration)
public void tearDown() {
f.delete();
}
}
@State(Scope.Thread)
static public class BenchmarkPlainIntSetup {
public RandomAccessFile raf;
public File f;
@Setup(Level.Iteration)
public void setUp() {
try {
f = new File("jmhDirectIntBenchamrk.ser" + ThreadLocalRandom.current().nextInt());
raf = new RandomAccessFile(f, "rw");
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
@TearDown(Level.Iteration)
public void tearDown() {
f.delete();
}
}
}
绝对结果有差异(每次操作的毫秒数)
benchamrkWriteConvertedInt 0.008
benchamrkWriteDirectInt 0.026
不知道为什么(可能会在一段时间后挖掘程序集来理解,但我可以证实你的发现。问得好!)
这是 运行,最新 java-8 和 java-9 顺便说一句
RandomAccessFile实际上有两种写入字节的本地方法:
//writes an array
private native void writeBytes(byte b[], int off, int len) throws IOException;
和
//writes one byte
public native void write(int b) throws IOException;
方法 writeInt(int) 使用本机 write(int) 方法分别写入每个字节,而 write(byte[]) 使用本机 writeBytes(byte[],int,int) 方法。
writeInt 方法执行 4 次方法调用来写入传递的整数值的每个字节,另一种方法仅使用一次调用来写入数组。在 java 中,方法调用实际上是昂贵的操作:对于每次调用,JVM 都会为操作数堆栈和局部变量数组分配额外的内存。
我今天遇到了一件关于 RandomAccessFile
的有趣事情。
我注意到使用 RandomAccessFile
的 writeInt(int i)
方法比使用 RandomAccessFile
的 write(byte[] b)
方法慢得多,我首先将 int 值转换为 byte [4] 数组。
我正在使用此代码进行转换
private static byte[] intToByte(int i)
{
byte[] result = new byte[4];
result[0] = (byte) (i >> 24);
result[1] = (byte) (i >> 16);
result[2] = (byte) (i >> 8);
result[3] = (byte) (i);
return result;
}
差异非常显着,有利于write(byte[] b)
。
用 JDK 8:
在我的笔记本电脑上写 100 万int
s
- 通过
writeInt(int i)
方法花费了~9秒 - 通过
write(byte[] b)
花费了 ~2.3 秒
我在另一个环境中得到了类似的结果,我使用的是 JDK 7 和一台完全不同的机器。
writeInt(int i) 方法委托给本机 write0(int b)
方法,write(byte[] b)
委托给本机 writeBytes
.
当我进行分析时,我注意到大部分执行时间都花在了 writeInt
方法上。
有谁知道为什么我看到这么大的差异?似乎 writeInt
效率较低。
不打算详细说明我所做的更改,但您的测试有一点缺陷。我冒昧地对它们进行了一些更新,运行 也进行了一些测试:
@BenchmarkMode(value = { Mode.AverageTime })
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Warmup(iterations = 2, time = 2, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 2, time = 2, timeUnit = TimeUnit.SECONDS)
public class RandomAccessWriteFileTest {
public static void main(String[] args) throws Exception {
Options opt = new OptionsBuilder().include(RandomAccessWriteFileTest.class.getSimpleName())
.jvmArgs("-ea")
.shouldFailOnError(true)
.build();
new Runner(opt).run();
}
@Benchmark()
@Fork(1)
public long benchamrkWriteDirectInt(BenchmarkPlainIntSetup setupTest) {
try {
setupTest.raf.writeInt(6969);
return setupTest.raf.length();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Benchmark()
@Fork(1)
public long benchamrkWriteConvertedInt(BenchmarkConvertedIntSetup setupTest) {
try {
setupTest.raf.write(intToBytes(6969));
return setupTest.raf.length();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static byte[] intToBytes(int i) {
byte[] result = new byte[4];
result[0] = (byte) (i >> 24);
result[1] = (byte) (i >> 16);
result[2] = (byte) (i >> 8);
result[3] = (byte) i;
return result;
}
@State(Scope.Thread)
static public class BenchmarkConvertedIntSetup {
public RandomAccessFile raf;
public File f;
@Setup(Level.Iteration)
public void setUp() {
try {
f = new File("jmhDirectIntBenchamrk.ser" + ThreadLocalRandom.current().nextInt());
raf = new RandomAccessFile(f, "rw");
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
@TearDown(Level.Iteration)
public void tearDown() {
f.delete();
}
}
@State(Scope.Thread)
static public class BenchmarkPlainIntSetup {
public RandomAccessFile raf;
public File f;
@Setup(Level.Iteration)
public void setUp() {
try {
f = new File("jmhDirectIntBenchamrk.ser" + ThreadLocalRandom.current().nextInt());
raf = new RandomAccessFile(f, "rw");
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
@TearDown(Level.Iteration)
public void tearDown() {
f.delete();
}
}
}
绝对结果有差异(每次操作的毫秒数)
benchamrkWriteConvertedInt 0.008
benchamrkWriteDirectInt 0.026
不知道为什么(可能会在一段时间后挖掘程序集来理解,但我可以证实你的发现。问得好!)
这是 运行,最新 java-8 和 java-9 顺便说一句
RandomAccessFile实际上有两种写入字节的本地方法:
//writes an array
private native void writeBytes(byte b[], int off, int len) throws IOException;
和
//writes one byte
public native void write(int b) throws IOException;
方法 writeInt(int) 使用本机 write(int) 方法分别写入每个字节,而 write(byte[]) 使用本机 writeBytes(byte[],int,int) 方法。
writeInt 方法执行 4 次方法调用来写入传递的整数值的每个字节,另一种方法仅使用一次调用来写入数组。在 java 中,方法调用实际上是昂贵的操作:对于每次调用,JVM 都会为操作数堆栈和局部变量数组分配额外的内存。