Более быстрый способ получить числовую разницу между 2-байтовыми [] массивами? - PullRequest
1 голос
/ 09 апреля 2020

Я работаю над программой, в которой у меня есть 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 отсутствует, использование операций сокращения и сбора было бы невозможным без распаковки и упаковки.

Другой вариант - использовать IntStream.range(0, byteArrayLength) для создания параллельного потока и доступа к индексу с помощью int. , Однако для этого потребуется LongAdder или AtomicLong, оба из которых намного медленнее в моих тестах. (LongAdder, кажется, использует массив внутри, а затем суммирует его в конце)

Есть ли более эффективный способ добиться этого? Я не против добавления внешних зависимостей. Спасибо!

1 Ответ

3 голосов
/ 09 апреля 2020

Одна вещь, которую вы можете попробовать, это разделить данные на две или более области, каждая из которых обрабатывается в отдельных потоках. Это может иметь значение для массивов из миллиарда элементов, чтобы оно того стоило, но всего для 5 миллионов, вероятно, нет.

Ниже приводится очень грубое доказательство концепции, которое вы можете использовать, чтобы оценить, имеет ли идея какую-либо ценность.

Создать метод, который выполняет вычисления для региона:

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();
}
...