У меня есть код, который потребляет большое количество (миллионы в настоящее время, в конечном итоге миллиарды) относительно коротких (5-100 элементов) массивов случайных чисел и выполняет с ними не очень напряженную математику. Случайные числа, ну, случайные, в идеале я хотел бы генерировать их на нескольких ядрах, поскольку генерация случайных чисел составляет> 50% моего времени выполнения при профилировании. Однако у меня возникли трудности с распределением большого количества небольших задач таким образом, чтобы это было не медленнее, чем однопоточный подход.
Мой код в настоящее время выглядит примерно так:
for(int i=0;i<1000000;i++){
for(RealVector d:data){
while(!converged){
double[] shortVec = new double[5];
for(int i=0;i<5;i++) shortVec[i]=rng.nextGaussian();
double[] longerVec = new double[50];
for(int i=0;i<50;i++) longerVec[i]=rng.nextGaussian();
/*Do some relatively fast math*/
}
}
}
Подходы, которые я использовал, но которые не сработали:
- 1+ потоков, заполняющих ArrayBlockingQueue, и мой основной цикл, потребляющий и заполняющий массив (упаковка/распаковка здесь была убийцей)
- Генерация векторов с помощью Callable (получение будущего) при выполнении независимых частей математики (похоже, накладные расходы на косвенность перевешивают любые преимущества параллелизма, которые я получил)
- Использование 2 ArrayBlockingQueue, каждая из которых заполняется потоком, один для коротких и один для длинных массивов (все еще примерно в два раза медленнее, чем прямой однопоточный случай).
Я не столько ищу «решения» своей конкретной проблемы, сколько как справиться с общим случаем параллельной генерации больших потоков небольших независимых примитивов и их потребления из одного потока.