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

时间:2012-12-27 18:43:07

标签: java android performance deserialization protocol-buffers

我需要在启动Android应用程序时快速加载大约2MB的数据。 我真的需要在内存中所有这些数据,所以像SQLite等不能替代它。

数据包含大约3000个int[][]数组。数组维数平均约为[7] [7]。

我首先在桌面上实现了一些原型,并将其移植到了android。在桌面上,我只使用了Java(de)序列化。在我的桌面计算机上反序列化该数据大约需要90毫秒。

然而,在Android 2.2.1上,同样的过程在我的HTC Magic上大约需要15秒(!)。它是如此之慢,如果我不在单独的thred中反序列化,我的应用程序将被杀死。总而言之,这是令人无法接受的缓慢。

我做错了什么?我应该

  • 切换到协议缓冲区之类的内容?这真的会加速几个级别的反序列化过程 - 毕竟,我反序列化并不是复杂的对象,只是int[][]数组?!
  • 设计我自己的自定义二进制文件格式?我以前从未这样做过,也没有任何线索从哪里开始
  • 做点什么吗?

4 个答案:

答案 0 :(得分:4)

为什么不绕过内置的反序列化,并使用直接二进制I / O? 当速度是你最关心的问题,不一定是编程的简易性,你就无法击败它。

对于输出,伪代码看起来像这样:

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

对于输入,伪代码为:

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

当您以二进制读取/写入数字时,可以绕过二进制和字符之间的所有转换。 速度应仅受文件存储介质的数据传输速率限制。

答案 1 :(得分:1)

在尝试了几件事之后,正如Mike Dunlavey建议的那样,直接二进制I / O似乎最快。我几乎逐字地使用了他的草图版本。但是,为了完整性,如果有人想尝试,我会在这里发布我的完整代码;即使它是非常基本的,没有任何形式的理智检查。这是为了读取这样的二进制流;写作绝对是类似的。

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;  
}

答案 2 :(得分:0)

几个月前我在一个项目上遇到了同样的问题。我认为你应该将文件分成不同的部分,并且只根据用户的选择加载相关的部分。 希望它会有所帮助!

答案 3 :(得分:-1)

我不知道您的数据,但如果您优化循环,则会令人难以置信地影响反序列化时间。

如果你看下面的例子

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
    }
}
相关问题