Java性能问题:需要通过目标分支检查来遍历800万条记录

时间:2019-05-01 17:00:19

标签: java performance function

我们有一个处理平面文件并(仅通过几次验证)插入数据库的系统。

此代码:

//There can be 8 million lines-of-codes

for(String line: lines){
   if (!Class.isBranchNoValid(validBranchNoArr, obj.branchNo)){
    continue;
   }
   list.add(line);
 }

isBranchNoValid的定义:

//the array length ranges from 2 to 5 only

public static boolean isBranchNoValid(String[] validBranchNoArr, String branchNo) {
  for (int i = 0; i < validBranchNoArr.length; i++) {
    if (validBranchNoArr[i].equals(branchNo)) {
        return true;
      }
       }
    return false;
    } 

验证是在行级别进行的(我们必须过滤或跳过数组中没有branchNo的行)。以前不是这样(过滤)。

现在,高性能降级正在困扰着我们。 我了解(可能是我错了),这种重复的函数调用导致大量stack创建,从而导致很高的GC调用。

我想不出一种方法(甚至有可能)来执行这种过滤器而不会造成性能降低的高昂代价(有一点点差别就可以了)。

2 个答案:

答案 0 :(得分:0)

这肯定不是堆栈问题,因为您的函数不是递归的,因此两次调用之间的堆栈中没有任何内容。每次调用后,变量将被删除,因为不再需要它们了。

您可以将有效数字放在一个集合中,并使用该数字进行一些优化,但对于您而言,由于您最多有5个元素,因此我不确定它是否会带来任何好处。

答案 1 :(得分:0)

因此,您的方案中可能存在几个瓶颈。

  1. 读取文件的行
  2. 解析该行以构造要插入数据库的对象
  3. 检查对象的适用性(即无过滤分支)
  4. 插入数据库

通常,您会说IO是最慢的,所以1.和2.您什么也没说,除了2.已更改,对吧?太奇怪了。

无论如何,如果您想对其进行优化,那么我将不会传递约800万次该数组,并且也不会每次都对其进行迭代。由于您的有效分支是已知的,因此请从中创建一个HashSet-它具有O(1)访问权限。

Set<String> validBranches = Arrays.stream(branches)
                              .collect(Collectors.toCollection(HashSet::new));

然后,迭代行

for (String line : lines) {
    YourObject obj = parse(line);
    if (validBranches.contains(obj.branchNo)) {
        writeToDb(obj);
    }
}

或者,在流版本中

Files.lines(yourPath)
     .map(this::parse)
     .filter(o -> validBranches.contains(o.branchNo))
     .forEach(this::writeToDb);

我还将检查首先收集一批对象然后写入db效率是否更高。另外,如果解析需要大量时间,则并行处理这些行可能会提高速度。