0

我正在开发一个程序,其中我有 2 个字节数组并且需要计算它们之间的差异。例如,如果第一个数组是 {1, 2, 3},第二个数组是 {2, 3, 4},则差值为 3。

我目前执行此操作的方法如下所示:

public long calculateDifference(byte[] a, byte[] b) {
  long difference = 0;
  for(int i = 0; i < a.length; i++) {
    difference += Math.abs(a[i] - b[i]);
  }
  return difference;
}

但是,该程序需要能够处理最多包含大约 5,000,000 个元素的字节数组,因此使用当前方法会太慢。

因为我有 16 个线程,所以我将并行流视为一种选择。但是因为没有 ByteStream,所以如果没有拆箱和装箱,就无法使用 reduce 和 collect 操作。

另一种选择是IntStream.range(0, byteArrayLength)使用 int 创建并行流并访问索引。但是,要做到这一点,LongAdder 或 AtomicLong 是必要的,这两者在我的基准测试中都要慢得多。(LongAdder 似乎在内部使用了一个数组,然后在最后进行总结)

有没有更有效的方法来实现这一目标?我不介意添加外部依赖项。谢谢!

4

1 回答 1

2

您可以尝试的一件事是将数据分成两个或多个区域,每个区域在单独的线程中处理。对于包含 10 亿个项目的数组来说,它可能会产生足够的差异以使其物有所值,但对于少至 500 万个,可能不会。

接下来是一个非常粗略的概念验证,您可以使用它来评估这个想法是否有任何优点。

创建一个对区域进行计算的方法:

public long calculateDifference(byte[] a, byte[] b, int start, int end) {
    long difference = 0;
    for(int i = start; i < end; i++) {
        difference += Math.abs(a[i] - b[i]);
    }
    return difference;
}

并从多个线程调用此方法,并组合结果:

ExecutorService threadPool = Executors.newFixedThreadPool(2);

public long calculateDifference(byte[] a, byte[] b) throws Exception {
    Future<Long> diff1 = threadPool.submit(() -> calculateDifference2(a, b, 0, a.length / 2));
    Future<Long> diff2 = threadPool.submit(() -> calculateDifference2(a, b, a.length / 2, a.length));
    return diff1.get() + diff2.get();
}
于 2020-04-09T02:35:00.403 回答