【问题标题】:Faster way to get the numerical difference between 2 byte[] arrays?获得 2 字节 [] 数组之间数值差异的更快方法?
【发布时间】:2020-04-09 02:04:24
【问题描述】:

我正在开发一个程序,其中我有 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 内部好像用了一个数组,最后总结一下)

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

【问题讨论】:

  • 如果第一个数组是{1,2,3},第二个数组是{0}怎么办?此外,5,000,000 的添加可能花费的时间比您可以测量的要少。计算机每秒可以执行许多 数百万 次操作。 What is a gigaflop?2014 a Core i7 5930K 在 3.5GHz 的 6 核中有 289 gigaflops。
  • @ElliottFrisch 我实际上正在制作一个遗传算法并会持续运行它,因此即使速度提高 20%,也可以节省数小时。
  • @Joni 请看我上面的评论。
  • 注意 289 gigaflops 是 ~289,000,000,000 浮点 操作(每秒)。您将 500 万与近 3000 亿进行比较。小时?不需要几秒钟。
  • @ElliottFrisch 我实际上不知道时钟速度与每秒的浮点运算不同!但是,对于我的程序来说,吞吐量越大越好。

标签: java algorithm lambda java-stream array-difference


【解决方案1】:

您可以尝试的一件事是将数据分成两个或多个区域,每个区域在单独的线程中处理。对于 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();
}

【讨论】:

  • 感谢您的回答!只有两个问题:改用 threadPool.invokeAll() 会有所不同吗,threadPool 可以重用吗?
  • invokeAll 不会对计算性能产生影响,但如果您觉得方便,请使用它。当然,您可以重用线程池,但如果这样做,您最终可能会造成瓶颈,例如,如果 calculateDifference 本身是从不同的线程调用的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多