0

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

数据由大约 3000 个int[][]数组组成。数组维度平均约为 [7][7]。

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

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

我究竟做错了什么?我是不是该

  • 切换到协议缓冲区之类的东西?这真的会加快几个数量级的反序列化过程吗?毕竟,我要反序列化的不是复杂的对象,只是int[][]数组?!
  • 设计我自己的自定义二进制文件格式?我以前从未这样做过,也不知道从哪里开始
  • 做别的事?
4

4 回答 4

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

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

于 2012-12-27T19:11:08.987 回答
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;  
}
于 2013-02-03T17:56:56.233 回答
0

几个月前,我在一个项目中遇到了同样的问题。我认为您应该将文件拆分为各个部分,并且仅在用户选择之后才加载相关部分。希望它会有所帮助!

于 2012-12-27T18:45:46.890 回答
-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
    }
}
于 2012-12-27T19:26:32.493 回答