好吧,在我提出问题之前,我想首先指出我知道Serializable和Exernalizable之间的区别,所以你不需要给出解释!
我基本上要做的是将一个包含所有数据的类保存在一个文件中。 我们已经到了Java 9已经出现并且JVM非常快的时候,但是仍然有人(我相信他们认为)与使用Exernalizable相比,在大量数据上使用Serializable是非常低效的。
如果我只有10个代表整数或布尔等普通数据类型的字段,我绝对会使用Serializable。
但现在我得到了更多的数据来存储和加载,例如一个3维字节数组,包含大约330万个字段,我认为通过Serializable类实现的反射方式保存这样的数据效率非常低。但由于我不能100%确定可以在存储如此大量数据时更加高效的Exernalizable方式,所以我想在开始使用我的程序之前先确保自己,因为它不需要快速保存数据但是加载速度非常快(而且不仅一次,它需要先进行一些计算,然后在程序中多次加载它,因为根据程序所处的状态需要加载不同的数据集)。所以基本上我的想法是我会在Externalizable#readExternal()函数中通过异步多线程加载字节数组。
如果我认为在这里使用Exernalizable并不是更有效的方式我错了,请纠正我,因为我希望程序在加载数据时尽可能流畅地运行!
敬意,
Fabian Schmidt!
答案 0 :(得分:-1)
基本上我现在所做的就是比较通过反射/我自己的实现来保存/加载所需的时间。
测试代码:
主类(Comparision.class)
package de.cammeritz.chunksaver.util;
import java.io.File;
/**
* Created by Fabian / Cammeritz on 20.10.2017 at 03:15.
*/
public class Comparision {
public static void main(String args[]) {
long start;
long end;
//Preparing datasets
DataSerializable dataSerializable = createSerializable();
DataExternalizable dataExternalizable = createExternalizable();
//Storage files
File sFile = new File(System.getProperty("user.dir"), "sFile.dat");
File eFile = new File(System.getProperty("user.dir"), "eFile.dat");
//Saving via reflection
start = System.currentTimeMillis();
FileUtil.save(dataSerializable, sFile);
end = System.currentTimeMillis();
System.out.println("Time taken to save via reflection in milliseconds: " + (end - start));
//Saving via my own code
start = System.currentTimeMillis();
FileUtil.save(dataExternalizable, eFile);
end = System.currentTimeMillis();
System.out.println("Time taken to save via my own code in milliseconds: " + (end - start));
//Loading via reflection
start = System.currentTimeMillis();
dataSerializable = (DataSerializable) FileUtil.load(sFile);
end = System.currentTimeMillis();
System.out.println("Time taken to load via reflection in milliseconds: " + (end - start));
//Loading via my own code
start = System.currentTimeMillis();
dataExternalizable = (DataExternalizable) FileUtil.load(eFile);
end = System.currentTimeMillis();
System.out.println("Time taken to save via my own code in milliseconds: " + (end - start));
}
private static DataSerializable createSerializable() {
DataSerializable data = new DataSerializable(7);
for (int cx = 0; cx < data.getSideSize(); cx++) {
for (int cz = 0; cz < data.getSideSize(); cz++) {
for (int x = 0; x < data.getX(); x++) {
for (int y = 0; y < data.getY(); y++) {
for (int z = 0; z < data.getZ(); z++) {
data.setValue(cx, cz, x, y, z, (byte) 0x7f);
}
}
}
}
}
return data;
}
private static DataExternalizable createExternalizable() {
DataExternalizable data = new DataExternalizable(7);
for (int cx = 0; cx < data.getSideSize(); cx++) {
for (int cz = 0; cz < data.getSideSize(); cz++) {
for (int x = 0; x < data.getX(); x++) {
for (int y = 0; y < data.getY(); y++) {
for (int z = 0; z < data.getZ(); z++) {
data.setValue(cx, cz, x, y, z, (byte) 0x7f);
}
}
}
}
}
return data;
}
}
通过反思进行序列化:
package de.cammeritz.chunksaver.util;
import java.io.Serializable;
/**
* Created by Fabian / Cammeritz on 20.10.2017 at 02:59.
*/
public class DataSerializable implements Serializable {
private final int x = 16;
private final int y = 256;
private final int z = 16;
private byte[][][][][] ids = null;
private int sideSize;
public DataSerializable(int sideSize) {
this.sideSize = sideSize;
ids = new byte[sideSize][sideSize][16][256][16];
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getZ() {
return z;
}
public int getSideSize() {
return sideSize;
}
public byte getValue(int cx, int cz, int x, int y, int z) {
return ids[cx][cz][x][y][z];
}
public void setValue(int cx, int cz, int x, int y, int z, byte value) {
ids[cx][cz][x][y][z] = value;
return;
}
}
通过我自己的实现进行分类:
package de.cammeritz.chunksaver.util;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Created by Fabian / Cammeritz on 20.10.2017 at 02:58.
*/
public class DataExternalizable implements Externalizable {
private final int x = 16;
private final int y = 256;
private final int z = 16;
private byte[][][][][] ids = null;
private int sideSize;
public DataExternalizable() {
}
public DataExternalizable(int sideSize) {
this.sideSize = sideSize;
ids = new byte[sideSize][sideSize][16][256][16];
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getZ() {
return z;
}
public int getSideSize() {
return sideSize;
}
public byte getValue(int cx, int cz, int x, int y, int z) {
return ids[cx][cz][x][y][z];
}
public void setValue(int cx, int cz, int x, int y, int z, byte value) {
ids[cx][cz][x][y][z] = value;
return;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(ids);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
ids = (byte[][][][][]) in.readObject();
}
}
基本上我同意@markspace上面所说的内容(“我认为Serializable很慢的想法已经相当陈旧了。像7和8这样的现代JVM实现了很多加速,以帮助Serializable运行得更快。我会开始有了这个,只进一步调查,如果它实际上运行慢于可接受的“) 以及@EJP所说的话(“我认为@markspace在这里的钱是正确的。你不需要它尽可能快,你需要它足够快。在过去我们不得不进行排序 - 合并得足够快,所以他们没有遇到第二次操作员转移。任何比这更快的实际上没有回报。“)
现在测试的问题是结果非常混乱,并且表明我肯定会在这里使用Externalizable。
3个测试的结果具有相同的值和确切的数据集大小我将在我的项目中稍后使用:
Time taken to save via reflection in milliseconds: 746
Time taken to save via my own code in milliseconds: 812
Time taken to load via reflection in milliseconds: 3191
Time taken to save via my own code in milliseconds: 2811
Time taken to save via reflection in milliseconds: 755
Time taken to save via my own code in milliseconds: 934
Time taken to load via reflection in milliseconds: 3545
Time taken to save via my own code in milliseconds: 2671
Time taken to save via reflection in milliseconds: 401
Time taken to save via my own code in milliseconds: 784
Time taken to load via reflection in milliseconds: 3065
Time taken to save via my own code in milliseconds: 2627
让我感到困惑的是,反射实现的保存速度明显快于我自己的实现,但相反,加载数据需要大约1秒的时间。
现在的观点是,这1秒对于我计划要做的事情非常重要,因为保存并不重要,但加载必须快速完成。所以结果清楚地告诉我,我应该在这里使用Externalizable方式。
但是,有人可以告诉我为什么反射方式更快地存储以及如何改进我自己的保存数据实现?
感谢所有人!