Как уже указывалось, использование критических разделов замедлит работу, поскольку в этом разделе одновременно разрешен только 1 поток. Абсолютно нет необходимости использовать критические разделы, поскольку каждый поток записывает во взаимоисключающие разделы данных, при этом чтение неизмененных данных, очевидно, не нуждается в защите.
Мое подозрение относительно медлительности кода сводится к неравномерному распределению работы по потокам. По умолчанию я думаю, что openmp делит итерации поровну между потоками. В качестве примера рассмотрим, когда у вас есть 8 потоков и 8 баллов:
- нить 0 получит 7 расчетов расстояния
-притаска 1 получит 6 расчетов расстояния
...
-приточка 7 получит 0 вычислений расстояния
Даже при большем количестве итераций подобное неравенство все еще существует. Если вам нужно убедить себя, создайте частный счетчик потока, чтобы отслеживать, сколько вычислений фактически выполняется каждым потоком.
С такими конструкциями разделения работы, как параллель, вы можете указать различные стратегии распределения работы. В вашем случае, вероятно, лучше пойти с
#pragma omp for schedule(guided)
Когда каждый поток запрашивает несколько итераций цикла for, он получает количество оставшихся циклов (еще не переданных потоку), деленное на количество потоков. Итак, изначально вы получаете большие блоки, позже вы получаете меньшие блоки. Это форма автоматического распределения нагрузки, учтите, что есть некоторые (возможно, небольшие) издержки при динамическом распределении итераций между потоками.
Чтобы не допустить, чтобы первый поток получил неоправданно большой объем работы, ваша структура циклов должна быть изменена таким образом, чтобы на более низких итерациях было меньше вычислений, например измените внутренний цикл for на
for (j=0; j<p-1; j++)
Еще одна вещь, которую следует учитывать, - при работе с большим количеством ядер память может стать узким местом. У вас есть 8 процессоров, борющихся за, вероятно, 2 или 3 канала DRAM (отдельные карты памяти на одном и том же канале все еще конкурируют за пропускную способность). Кэш-память ЦП на кристалле в лучшем случае распределяется между всеми процессорами, поэтому кэш-память у вас по-прежнему не больше, чем серийная версия этой программы.