【问题标题】:Android performance issues in populating ArrayList填充 ArrayList 时的 Android 性能问题
【发布时间】:2014-01-09 05:22:50
【问题描述】:

我创建了一种方法来根据从服务器获得的 Http 响应填充数组。我以简单的格式收到回复并使用扫描仪阅读。响应只有大约 8000 个条目(浮点数和整数),填充 ArrayList 需要很长时间,大约需要 1 或 2 分钟。这是代码

public void update(String str) {
    ProgressDialog pDialog = new ProgressDialog(context);
    pDialog.setMessage("Atualizando pesos, aguarde");
    pDialog.show();
    BufferedReader r = new BufferedReader(new StringReader(str));
    Scanner s = null;
    try{
        s = new Scanner(r);
        ArrayList<ArrayList<ArrayList<Double> > > weights = new ArrayList<ArrayList<ArrayList<Double> > >();
        while(s.hasNextInt()){
            ArrayList<ArrayList<Double> > wl = new ArrayList<ArrayList<Double> >();
            int layerId = s.nextInt(), neuronsAmt = s.nextInt(), inputSize = s.nextInt();
            Log.d("UpdateTask",  "Layer " + layerId + ", neuronios: " + neuronsAmt + ", inputSize: " + inputSize);
            for(int i = 0; i < neuronsAmt; i++){
                ArrayList<Double> wi = new ArrayList<Double>(); 
                for(int j = 0; j < inputSize; j++){
                    wi.add(s.nextDouble());
                }
                wl.add(wi);
            }
            weights.add(wl);
            this.weights = weights;
            if(s.hasNext() && !s.hasNextInt())
                Log.d("UpdateTask", "Depois de tudo tem " + s.next());
        }
    }finally{
        if( s != null) s.close();
        pDialog.dismiss();
    }   
}

我在收到 HTTP 响应后从 AsyncTask 调用它。

编辑:我将尝试在此处解释 HTTP 结构。响应实际上给出了神经网络的权重。基本上它是一个矩阵数组(应该保留为矩阵,以便神经网络的评估工作)。 HTTP 响应如下: 有N个矩阵。每一个都以一个整数(矩阵 ID)开头,然后是矩阵中的行数(R)和列数(C)。之后,有 R*C 浮点数表示存储在矩阵中的值。当您找不到另一个图层 id 时,输入将终止。

PS:我也无法让对话框工作,但现在这对我来说不是问题。

【问题讨论】:

  • 你为什么使用 ArrayList>>?
  • 它实际上是一个矩阵数组(这些是我正在尝试做的神经网络中的权重)。我只是不知道更好的方法(我刚开始用 Java 编写代码)。
  • 嗯,我不知道确切的效果,但我可以想象这非常低效。
  • 发布(结构)来自 HTTP 请求的响应。你的储蓄方式看起来效率很低。
  • 真的需要weights 和this.weights;不能直接加this一个吗?

标签: java android performance arraylist io


【解决方案1】:

考虑简化您的数组结构,即尽可能使用随意的array。在可能的情况下,还要用容量初始化ArrayList(如leandrocastelli 所述)。例如,您的代码可能会这样优化:

    ...

    try {
        s = new Scanner(r);
        ArrayList<double[][]> weights = new ArrayList<double[][]>(); // capacity is highly recommended here, even approximate
        while(s.hasNextInt()){

            int layerId = s.nextInt(), neuronsAmt = s.nextInt(), inputSize = s.nextInt();
            double[][] wl = new double[neuronsAmt][]; // just 2D-array of doubles, which is much faster than List of List

            Log.d("UpdateTask",  "Layer " + layerId + ", neuronios: " + neuronsAmt + ", inputSize: " + inputSize);
            for(int i = 0; i < neuronsAmt; i++){
                double[] wi = new double[inputSize]; 
                for(int j = 0; j < inputSize; j++){
                    wi[j] = s.nextDouble();
                }
                wl[i] = wi;
            }
            weights.add(wl);
            this.weights = weights;
            if(s.hasNext() && !s.hasNextInt())
                Log.d("UpdateTask", "Depois de tudo tem " + s.next());
        }
    }
    ...

【讨论】:

  • 我知道应该改进它,但它会产生严重的影响吗?我的意思是,这个 3d ArrayList 中的项目总数约为 8000,它应该不会有太大的区别,对吧?我的意思是,现在填充 ArrayList 需要超过 1 分钟。
  • 你可以试试,简单明了的优化。要 100% 确定导致延迟的原因,请profile 您的方法。
  • 接受“个人资料”提示的答案,谢谢,我会尽快尝试。
【解决方案2】:

如果您知道 ArrayList 的条目数量(或至少对此有所了解),请使用此容量对其进行实例化。像这样:

 //N is the number of matrices that you are expceting
 ArrayList<ArrayList<ArrayList<Double> > > weights = new ArrayList<ArrayList<ArrayList<Double> > >(N);
  while(s.hasNextInt()){

  ArrayList<ArrayList<Double> > wl = new ArrayList<ArrayList<Double> >(R); 
  int layerId = s.nextInt(), neuronsAmt = s.nextInt(), inputSize = s.nextInt();
  for(int i = 0; i < neuronsAmt; i++){
        ArrayList<Double> wi = new ArrayList<Double>(inputSize); 
            for(int j = 0; j < inputSize; j++){
                wi.add(s.nextDouble());
            }
            wl.add(wi);
  }

【讨论】:

  • 我希望数据位于锯齿状 3d 数组中,因为原始帖子使用 3 个嵌套的 ArrayList。
  • 嗯,是一样的。只需用近似值实例化每一个。
  • 不用,正常使用add函数
  • 知道了,我以为和C++中的向量构造函数一样。
【解决方案3】:

在此处讨论的其他优化之后,结果要好得多。 问题是 Scanner 真的很慢,在 Android 设备中它变得更慢。这可能是由于它在后台进行的缓冲量,我不知道。

我使用了编程竞赛中的一个技巧:标记输入字符串并逐个解析值。结果很棒:我可以在不到一秒的时间内填充 ArrayList。

这是我现在得到的,工作得很好:

    ...
    String[] tokens = str.trim().split(" ");
    weights = new ArrayList<Double[][]>();
    int begin = 0;
    while(begin < tokens.length){
        int layerId = Integer.parseInt(tokens[begin]), neuronsAmt = Integer.parseInt(tokens[begin+1]), inputSize = Integer.parseInt(tokens[begin+2]);
        begin += 3;
        Double[][] wl = new Double[inputSize][neuronsAmt];
        Log.d("UpdateTask",  "Layer " + layerId + ", neuronios: " + neuronsAmt + ", inputSize: " + inputSize);
        for(int i = 0; i < inputSize; i++){ 
            for(int j = 0; j < neuronsAmt; j++){
                wl[i][j] = Double.valueOf(tokens[begin+i*neuronsAmt+j]);
            }
        }
        begin += inputSize*neuronsAmt;
        weights.add(wl);
    }
    ...

【讨论】:

    猜你喜欢
    • 2020-02-13
    • 2011-08-13
    • 2013-10-28
    • 1970-01-01
    • 2015-03-15
    • 2015-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多