【问题标题】:Serializable or Exernalizable with huge datasets, which one is faster and more practicable?Serializable 或 Exernalizable 与庞大的数据集,哪个更快,更实用?
【发布时间】:2018-04-01 02:48:06
【问题描述】:

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

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

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

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

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

国王的问候,

法比安·施密特!

【问题讨论】:

  • 易于测试和测量。 Externalizable 不必做 Serializable 所做的所有反射,但在编码和维护方面需要做更多的工作。
  • 我认为Serializable 很慢的想法已经过时了。像 7 和 8 这样的现代 JVM 实现了很多加速,以帮助 Serializable 运行得更快。我会从这个开始,只有在它实际上运行速度低于可接受的速度时才会进一步调查。
  • 那么我认为最好的方法就是比较两种方法和保存/加载数据的时间。
  • 我认为@markspace 是正确的。你不需要它尽可能快,你需要它快足够。在过去,我们必须以足够快的速度进行排序合并,以免他们遇到第二次操作员轮班。任何比这更快的都没有回报。
  • 好吧,你们两个现在看到了,到目前为止,这很明显有所不同,除了我的代码中的某些内容可以在导出实现中更有效地完成,但我确实认为我以最好的方式实现了它!

标签: java serialization serializable externalizable


【解决方案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 方式。

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

谢谢大家!

【讨论】:

  • 明确说明您在哪里使用Serializable,以及您在哪里使用Externalizable。关于“使用反射”与“使用我自己的代码”的部分毫无意义,因为您实际上同时使用Serializable(通过writeObject(byte[][][][][]),因此在这两种情况下都使用反射。
  • 好吧,让我明白我可能解释错了什么。我很困惑,保存 DataSerializable 比保存 DataExternalizable 类更快。但相反,加载 DataSerializable 比加载 DataExternalizable 类花费更多的时间!
  • 这真的没有意义,尤其是你没有按要求澄清。如果Externalizable 代码完全绕过序列化,只写出数组维度和实际最低级别的字节数组,并以相同的方式读回它们,只使用DataInputDataOutput。 .
猜你喜欢
  • 1970-01-01
  • 2012-06-09
  • 1970-01-01
  • 1970-01-01
  • 2018-06-01
  • 1970-01-01
  • 2014-05-17
  • 2014-10-12
  • 2023-03-12
相关资源
最近更新 更多