#c #arrays #algorithm #search #openmp
#c #массивы #алгоритм #Поиск #openmp
Вопрос:
Я пытаюсь оптимизировать поиск в массиве, чтобы создать максимально быстрый алгоритм с помощью omp. Прямо сейчас это занимает слишком много времени (около 5-10 минут на 4 ядрах, 8 потоков linux)
У меня есть большой 2D массив комбинаций, в котором хранится комбинация и ее идентификатор (не связанный с индексом массивов).
В этом массиве мне нужно найти комбинации, которые имеют одинаковое значение, но другой идентификатор.
Размер массива или комбинаций, combinationsSize, может варьироваться от 600 000 до 3 000 000. Однако идентификаторы находятся в диапазоне от 0 до 500.
итак, я попробовал следующее. Он работает довольно прилично с размером ниже 90 КБ (около 5 секунд), но большие массивы занимают целую вечность.
#pragma omp parallel for schedule(dynamic)
for(unsigned int i=0; i<combinationsSize; i )
{
for(unsigned int j=i 1; j<combinationsSize; j )
{
// if different ids
if(combinations[i][1] != combinations[j][1])
{
// if the same combination
if(combinations[i][0] == combinations[j][0])
{
// omp critical add to another array
}
}
}
}
У меня также есть возможность хранить комбинации в 3D-массиве, где
они хранятся в порядке идентификатора, но 2-й член может иметь любой размер, в зависимости от того, сколько у него комбинаций.
Однако это также приводит к длительным вычислениям (я предполагаю, из-за кэша) вот код:
for(int id1=0; id1<maxIDs; id1 )
{
#pragma omp parallel for schedule(dynamic,1)
for(unsigned int i=0; i<idSizes[id1]; i )
{
for(int id2=id1 1; id2<maxIDs; id2 )
{
for(unsigned int j=0; j<idSizes[id2]; j )
{
if(combinations[id1][i][0] == combinations[id2][j][0])
{
//omp critical add to another array
}
}
}
}
}
idSizes = — это массив, в котором хранится размер каждой из комбинаций идентификаторов в 3D-массиве
Максимальные значения = 500
Я перепробовал много разных подходов (логических, а также проб и ошибок) параллельного for, динамического расписания и т. Д. безрезультатно.
Просто перефразирую: моя цель — оптимизировать этот поиск в массиве, чтобы он мог выполнить задачу за считанные секунды, если это возможно. Он хранится в 2D и 3D массивах, поскольку с ними поступает другая информация, однако это не имеет значения в рамках этого вопроса.
РЕДАКТИРОВАТЬ, извините, я должен был упомянуть об этом: что касается критических значений, у меня есть критическое значение omp { добавьте эти идентификаторы и комбинации в массив}, мне это нужно.
Комментарии:
1.
number
вводит очень проблематичную зависимость. вы можете улучшить его, присвоив каждому заданию свой собственный счетчик (объявивnumber
его как omp private и записываяnum[i]=number;
, когда каждое задание выходитj
из цикла), и выполнить окончательную суммуnum[]
, когда openmp выходитi
из цикла.2. @user3528438, и это именно то, что
reduction( :number)
делает.3. но если вы посмотрите на проблему, вы обнаружите, что нет необходимости использовать подход грубой силы. вы можете сначала отсортировать все это по комбинации, затем в каждой ячейке отсортировать его по идентификатору. тогда вы можете в значительной степени уменьшить его до O (n).
4. В идеале вы должны записать это в форме, подходящей для внутреннего цикла simd vector и параллельного внешнего цикла omp, возможно, в зависимости от вашего выбора компилятора.
5. Устранение критического из внутреннего цикла было бы первоочередной задачей; тогда вам понадобится векторизованный внутренний цикл, даже если вы не используете параллельный omp.