Страницы

Поиск по вопросам

четверг, 19 марта 2020 г.

Как на Java параллельно сложить два массива?

#java #массивы #распараллеливание


Например, есть два огромных (длина 2-3 млн.) массива float[] или double[] без разницы.
Нужно их очень быстро сложить. Как это сделать? Есть ли какие-нибудь библиотеки для
этого?     


Ответы

Ответ 1



Я про 8 Java и LambdaJ написал скорее для общего ознакомления и для ответа на коммент про аналоги LINQ. Если отвечать в рамках вопроса, то ни LINQ, ни Java 8 и ни LambdaJ не является быстрым решением вопрооса сложения (с точки зрения производительности). Сложение слишком простая операция и накладные расходы на вского рода вкусности, вроде функционального стиля, будут слишком велики. Согласно докам по LambdaJ она в два раза медленее в среднем чем просто циклы. (В некоторых местах доходит до 4х раз). Новая Java все еще не в релизе, и пользоваться ей в продакшене не стоит. Остается только ручная многопоточность (мне кажется что 2-3 миллиона это не такие уж и огромные данные для операции сложения). На своем дряхленьком нетбуке я смог ускоритсья на двух тредах. Выложил код на гитхаб, надеюсь ктонить попробует и выложит информацию с нормального железа. Насчет использования с++ и SSE, следующий код: for (int i = 0; i < a.length; i++) c[i] = a[i] + b[i]; Компилится в SSE инструкции JIT'ом. Насколько будет выйгрыш, если вручную написать на SSE - не знаю. Возможно не стоит заморачиваться с нативным кодом.

Ответ 2



Это ответ не по теме, но возможно, другим участникам сайта он пригодится в будущем. В .NET PLINQ умеет самостоятельно разбить задание на нужное количество потоков (определяемое количеством процессоров/ядер на хосте) и выполнить операцию параллельно по частям. int length = Math.Min(arr1.Length, arr2.Length); double[] results = ParallelEnumerable.Range(0, length).AsOrdered() .Select(index => arr1[index] + arr2[index]) .ToArray(); Update: Как верно заметил @IronVbif, «наивный» PLINQ медленнее цикла, выполненного вручную. Однако на этот случай у .NET есть специальная перегрузка: int length = Math.Min(arr1.Length, arr2.Length); double[] results = new double[length]; var rangePartitioner = Partitioner.Create(0, length); Parallel.ForEach(rangePartitioner, (range, loopState) => { for (int i = range.Item1; i < range.Item2; i++) result[i] = arr1[i] + arr2[i]; }); (выполняется существенно быстрее, чем простое сложение).

Комментариев нет:

Отправить комментарий