OMP для вложенных циклов в VS2017

avatar
mitxael
8 апреля 2018 в 00:23
146
1
0

Я новичок в использовании OpenMP 2.0 вместе с MSVC++ 2017. Я работаю с большой структурой данных (обозначенной как bigMap), поэтому мне нужно распределять рабочую нагрузку при итерации наилучшим возможным способом. Моя попытка сделать это:

std::map<int, std::set<std::pair<double, double>>> bigMap;
///thousands of values are added here

int k;
int max_threads = omp_get_max_threads();
omp_set_num_threads(max_threads);
#pragma omp parallel default(none) private(k)
{
  #pragma omp for
  for(k = kMax; k > kMin; k--)
  {
    for (auto& myPair : bigMap[k])
    {
      int pthread = omp_get_thread_num();
      std::cout << "Thread " << pthread << std::endl;
      for (auto& item : myPair)
      {
         #pragma omp critical
         myMap[k-1].insert(std::make_pair(item, 0));
       }
    }
}

Вывод для "pthread" всегда равен "0", а время выполнения такое же, как и для одиночного потока (поэтому я предполагаю, что новые потоки не создаются). Почему этот код не работает и какой omp Директивы <7> / пункты / Разделы <4593510783>

ОБНОВЛЕНИЕ:

OMP теперь работает, но приведенный ниже код работает не так, как ожидалось:

#pragma omp parallel for schedule(static,1)
for (int i = 0; i < map_size; ++i) {
    #pragma omp critical
    bigMap[i] = std::set<int>();
}
bigMap[1] = { 10, 100, 1000 };

int i;
#pragma omp parallel for schedule(static) num_threads(8)
for (i = thread_num; i < map_size; i += thread_count)
{
    for (auto it = bigMap[i].begin(); it != bigMap[i].end(); ++it)
    {
        int elem = *it;
        bigMap[i + 1].insert(elem);
    }
}

Я ожидаю, что 3 элемента из bigMap[1] будут вставлены во все записи bigMap, вместо этого они вставлены только один раз, для bigMap[2], почему??

Источник
zzxyz
8 апреля 2018 в 00:39
0

Вы пробовали тот же код под clang или gcc? На данный момент я бы с осторожностью относился к реализации MSVC. Он старый, и М.С. об этом необычно молчит даже для них.

tim18
8 апреля 2018 в 04:33
0

std::cout будет сериализован, и вы сериализовали внутренний цикл, добавив критический, так что вы не можете ожидать параллельного ускорения. Если бы вы изменили направление внешнего omp, не было бы причин, по которым Microsoft OpenMP должен отставать (хотя он не обновлялся с VS2005).

mitxael
8 апреля 2018 в 09:00
0

@zzxyz, я этого не делал, потому что для этого я привязан к MSVC, в противном случае я был бы рад использовать материалы, доступные для версий OMP> 3, такие как задачи и пользовательские сокращения. Поэтому я должен выяснить, как заставить его работать на MSVC...

mitxael
8 апреля 2018 в 09:04
0

@ tim18 Я не заметил, что std::cout будет сериализован, но на самом деле это так, даже если он добавлен только для проверки. Что касается реверсирования внешнего omp для , я не понял вашей точки зрения, вы имеете в виду, что если я реверсирую его обратно, он будет работать лучше? Спасибо

zzxyz
9 апреля 2018 в 00:16
0

У MS есть собственная библиотека. Я бы, вероятно, использовал это для MS и использовал последнюю версию для всего остального. parallel_for и еще много чего на стороне MS. Тем не менее, может быть что-то не так с вашим кодом, который я пропустил.

mitxael
9 апреля 2018 в 00:42
0

@zzxyz Сначала я попробовал библиотеку параллелизма Microsoft <ppl.h>, но она у меня не работает, потому что я создаю внутреннюю библиотеку CLR («параллелизм не поддерживается при компиляции с /clr»). Удивительно, но OMP работает с /clr (MS запрещает использование PPL, но разрешает OMP...). Теперь OMP работает, но не так, как хотелось бы, я обновил свой вопрос текущим кодом.

Ответы (1)

avatar
David Daverio
10 апреля 2018 в 00:20
0

Маленькая ошибка....

#pragma omp parallel for schedule(static,1)
for (int i = 0; i < map_size; ++i) {
    #pragma omp critical
    bigMap[i] = std::set<int>();
}
bigMap[1] = { 10, 100, 1000 };

int i;
#pragma omp parallel for schedule(static) num_threads(8)
for (i = thread_num; i < map_size; i += thread_count)
{
    //here you loop on bigMap[i] which is empty execpt for i==1.
    //for (auto it = bigMap[i].begin(); it != bigMap[i].end(); ++it)
    for (auto it = bigMap[1].begin(); it != bigMap[1].end(); ++it)
    {
        int elem = *it;
        bigMap[i + 1].insert(elem);
    }
}

Возможно, вы не понимаете, что означает статика.