0

好吧,在我提出问题之前,我想先指出我知道 Serializable 和 Exernalizable 之间的区别,所以你不需要给出解释!

我基本上想做的是将一个类及其所有数据保存在一个文件中。我们已经到了 Java 9 出局并且 JVM 非常快的时代,但是仍然有人(我相信他们的观点)认为与使用 Exernalizable 相比,在大量数据上使用 Serializable 效率非常低。

如果我只有 10 个表示普通数据类型(如整数或布尔值)的字段,我肯定会使用 Serializable。

但是现在我有更多的数据要存储和加载,例如一个包含大约 330 万个字段的 3 维字节数组,我认为通过 Serializable 类实现的反射方式来保存这样的数据效率非常低. 但是由于我不能 100% 确定 Exernalizable 方式在存储如此大量的数据方面更有效,所以我想在开始使用我的程序之前先确保自己,因为它不需要快速保存数据但加载速度非常快(不仅是一次,它需要先进行一些计算,然后在程序期间多次加载它,因为根据程序所处的状态,它需要加载不同的数据集)。所以基本上我的想法是我将通过 Externalizable#readExternal() 函数中的异步多线程加载字节数组。

如果我认为在此处使用 Exernalizable 不是更有效的方法,请纠正我,因为我希望程序在加载数据时尽可能流畅地运行!

国王问候,

法比安·施密特!

4

1 回答 1

-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 方式。

但是这里的任何人都可以告诉我为什么反射方式保存得更快,以及我如何改进我自己的保存数据的实现?

谢谢大家!

于 2017-10-20T01:49:15.660 回答