简体   繁体   English

在应用程序启动时在Android中加载(反序列化)_quickly_ 2MB数据

[英]loading (deserializing) _quickly_ 2MB of Data in Android on Application Startup

I need to load around 2MB of data quickly on startup of my Android application. 启动Android应用程序时,我需要快速加载大约2MB的数据。 I really need all this data in memory, so something like SQLite etc. is not an alternative. 我真的需要所有这些数据在内存中,因此诸如SQLite之类的东西不是替代方案。

The data consists of about 3000 int[][] arrays. 数据由大约3000个int[][]数组组成。 The array dimension is around [7][7] on average. 阵列尺寸平均约为[7] [7]。

I first implemented some prototype on my desktop, and ported it to android. 我首先在桌面上实现了一些原型,然后将其移植到android。 On the desktop, I simply used Java's (de)serialization. 在桌面上,我只是使用Java的(反)序列化。 Deserialization of that data takes about 90ms on my desktop computer. 在我的台式计算机上,对这些数据进行反序列化大约需要90毫秒。

However on Android 2.2.1 the same process takes about 15seconds(!) on my HTC Magic. 但是,在Android 2.2.1上,我的HTC Magic上相同的过程大约需要15秒(!)。 It's so slow that if I don't to the deserialization in a seperate thred, my app will be killed. 它是如此之慢,以至于如果我不打算单独进行反序列化,我的应用程序将被杀死。 All in all, this is unacceptably slow. 总而言之,这太慢了。

What am I doing wrong? 我究竟做错了什么? Should I 我是不是该

  • switch to something like protocol buffers ? 切换到协议缓冲区之类的东西? Would that really speed up the process of deserialization of several magnitudes - after all, it's not complex objects that I am deserializing, just int[][] arrays?! 那真的会加速几个数量级的反序列化过程吗?毕竟,不是我要反序列化的复杂对象,而仅仅是int[][]数组?
  • design my own custom binary file format? 设计我自己的自定义二进制文件格式? I've never done that before, and no clue where to start 我以前从没做过,也不知道从哪里开始
  • do something else? 还有其他事吗

Why not bypass the built-in deserialization, and use direct binary I/O? 为什么不绕过内置的反序列化并使用直接二进制I / O? When speed is your primary concern, not necessarily ease of programming, you can't beat it. 当速度是您的首要考虑因素,不一定是易于编程时,您就无法超越它。

For output the pseudo-code would look like this: 为了输出,伪代码如下所示:

write number of arrays
for each array
  write n,m array sizes
  for each element of array
    write array element

For input, the pseudo-code would be: 对于输入,伪代码为:

read number of arrays
for each array
  read n,m array sizes
  allocate the array
  for each element of array
    read array element

When you read/write numbers in binary, you bypass all the conversion between binary and characters. 当您以二进制读取/写入数字时,将绕过二进制和字符之间的所有转换。 The speed should be limited only by the data transfer rate of the file storage media. 速度应仅受文件存储介质的数据传输速率限制。

after trying out several things, as Mike Dunlavey suggested, direct binary I/O seemed fastest. 在尝试了几件事之后,正如Mike Dunlavey所建议的那样,直接二进制I / O似乎是最快的。 I almost verbatim used his sketched out version. 我几乎逐字使用了他的草图版本。 For completeness however, and if someone else wants to try, I'll post my full code here; 为了完整起见,如果有人想尝试,我将在此处发布完整的代码。 even though it's very basic and without any kind of sanity check. 即使它是非常基本的,也没有任何类型的健全性检查。 This is for reading such a binary stream; 这是为了读取这样的二进制流; writing is absolutely analogous. 写作是绝对相似的。

import java.io.*;

public static int[][][] readBinaryInt(String filename) throws IOException {
    DataInputStream in = new DataInputStream(
            new BufferedInputStream(new FileInputStream(filename)));
int dimOfData = in.readInt();
int[][][] patternijk = new int[dimofData][][];
for(int i=0;i<dimofData;i++) {
    int dimStrokes = in.readInt(); 
    int[][] patternjk = new int[dimStrokes][];      
    for(int j=0;j<dimStrokes;j++) {
        int dimPoints = in.readInt();
        int[] patternk = new int[dimPoints];
        for(int k=0;k<dimPoints;k++) {
                patternk[k] = in.readInt();
            }
            patternjk[j] = patternk;
    }
    patternijk[i] = patternjk;
    }
    in.close();
return patternijk;  
}

I had the same kind of issues on a project some months ago. 几个月前,我在一个项目上遇到过类似的问题。 I think you should split your file in various parts, and only load relevant parts following a choice from the user for example. 我认为您应该将文件分成多个部分,并且仅在用户选择后才加载相关部分。 Hope it will be helpful! 希望对您有所帮助!

I dont know your data but if you optimize your loop, it will effect the deserialize time unbelievably. 我不知道您的数据,但是如果您优化循环,它将难以置信地影响反序列化时间。

if you look at example below 如果你看下面的例子

 computeRecursively(30); computeRecursivelyWithLoop(30); // 270 milisecond computeIteratively(30); // 1 milisecond computeRecursivelyFasterUsingBigInteger(30); // about twice s fast as before version computeRecursivelyFasterUsingBigIntegerAllocations(50000); // only 1.3 Second !!! 
public class Fibo {
    public static void main(String[] args) {
        // try the methods
    }

    public static long computeRecursively(int n) {

        if (n > 1) {
            System.out.println(computeRecursively(n - 2)
                    + computeRecursively(n - 1));
            return computeRecursively(n - 2) + computeRecursively(n - 1);
        }
        return n;
    }

    public static long computeRecursivelyWithLoop(int n) {
        if (n > 1) {
            long result = 1;
            do {
                result += computeRecursivelyWithLoop(n - 2);
                n--;
            } while (n > 1);
            System.out.println(result);
            return result;
        }
        return n;
    }

    public static long computeIteratively(int n) {
        if (n > 1) {
            long a = 0, b = 1;
            do {
                long tmp = b;
                b += a;
                a = tmp;
                System.out.println(a);
            } while (--n > 1);
            System.out.println(b);
            return b;
        }
        return n;
    }

    public static BigInteger computeRecursivelyFasterUsingBigInteger(int n) {
        if (n > 1) {
            int m = (n / 2) + (n & 1); // not obvious at first – wouldn’t it be
                                        // great to have a better comment here?
            BigInteger fM = computeRecursivelyFasterUsingBigInteger(m);
            BigInteger fM_1 = computeRecursivelyFasterUsingBigInteger(m - 1);
            if ((n & 1) == 1) {
                // F(m)^2 + F(m-1)^2
                System.out.println(fM.pow(2).add(fM_1.pow(2)));
                return fM.pow(2).add(fM_1.pow(2)); // three BigInteger objects
                                                    // created
            } else {
                // (2*F(m-1) + F(m)) * F(m)
                System.out.println( fM_1.shiftLeft(1).add(fM).multiply(fM));
                return fM_1.shiftLeft(1).add(fM).multiply(fM); // three
                                                                // BigInteger
                                                                // objects
                                                                // created
            }
        }
        return (n == 0) ? BigInteger.ZERO : BigInteger.ONE; // no BigInteger
                                                            // object created
    }

    public static long computeRecursivelyFasterUsingBigIntegerAllocations(int n) {
        long allocations = 0;
        if (n > 1) {
            int m = (n / 2) + (n & 1);
            allocations += computeRecursivelyFasterUsingBigIntegerAllocations(m);
            allocations += computeRecursivelyFasterUsingBigIntegerAllocations(m - 1);
            // 3 more BigInteger objects allocated
            allocations += 3;
            System.out.println(allocations);
        }
        return allocations; // approximate number of BigInteger objects
                            // allocated when
                            // computeRecursivelyFasterUsingBigInteger(n) is
                            // called
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM