Вопрос по openmp, c++, multithreading, parallel-processing, stl – c ++: OpenMP и контейнеры STL без произвольного доступа - возможный обходной путь

10

Таким образом, в SO и Интернет-сетях в целом существует много путаницы и разочарований по поводу того, как сделать OpenMP простым в использовании.#pragma директивы взаимодействуют с одинаково простыми в использовании контейнерами STL в C ++.

Все говорят об обходных путях для STLvector, но как насчет контейнеров с произвольным доступом / двунаправленнымmap, list, set, так далее. ?

Я столкнулся с этой проблемой и изобрел очень простой, очевидный обходной путь. Я представляю это здесь для STLmap, но это явно обобщаемо.

Серийная версия:

<code>for (std::map<A,B>::iterator it = my_map.begin();
        it != my_map.end();
        ++it)       
    { /* do work with  it   */  }
</code>

Мое предлагаемое решение использовать OpenMP с STLmap:

<code>    //make an array of iterators.
    int loop_length = my_map.size();
    std::map<A,B>::iterator loop_array[ loop_length ];

    std::map<A,B>::iterator allocate_it = my_map.begin();
    for (int j=0; j<loop_length; ++j)
        loop_array[j] = allocate_it++;

    // now you can use OpenMP as usual:
    #pragma omp parallel for
    for (uint j=0; j<loop_length; ++j) 
       { /* do work with    loop_array[j]    */  }
</code>

Я далеко не эксперт по OpenMP, однако, такI would like to know if my proposed work-around is efficient and good practice.

Пожалуйста, предположим, что программист отвечает за поточно-ориентированную обработку контейнера STL в цикле for.

Наконец, мое предложенное решение более эффективно, чем следующее обычно предлагаемое решение(см. ответ на этот вопрос), потому что, в моем решении, каждый поток не перебирает весь контейнер?

<code>#pragma omp parallel
{
    for (std::map<A,B>::iterator it = my_map.begin();
            it != my_map.end();
            ++it) 
    #pragma single nowait
       {   /*  do work  */   }

}
</code>
Извините, если мой вопрос глуп, но не могли бы вы просто повторитьj, а затем получить доступ к элементам черезallocate_it+j где разместить его, как в вашем посте. Azrael3000
@ larsmans Я не проводил никаких тестов производительности и тоже не планирую (извините). У меня уже есть большая, сложная программа, написанная последовательно, с контейнерами STL везде, и я пытаюсь многопоточность определенных циклов STL-for-for. Таким образом, я не могу легко изолировать и рассчитать время ... cmo
@ Azrael3000 Но арифметика итераторов действительна только для итераторов с произвольным доступом (например, дляvector)?map , list, set, используйте только двунаправленные итераторы. cmo
Я подозреваю, что это будет быстрее (по крайней мере, когдаA а такжеB большие, иначе вы можете просто скопировать их вvector). Но пытались ли вы решить эту проблему? Это было быстрее? Fred Foo
Нет, даже если вы скопируете содержимое контейнеров вvector для тестирования? Fred Foo

Ваш Ответ

1   ответ
5

OpenMP предоставляетtask построить, начиная с версии 3.0, которая очень полезна для использования с STL:

for (std::map<A,B>::iterator it = my_map.begin();
        it != my_map.end();
        ++it)       
{
   #pragma omp task
   { /* do work with  it   */  }
}

Конечно, для этой работы не должно существовать зависимости данных между итерациями.

Есть ли дополнительные издержки из-за наличия команды OpenMP внутри цикла? В общем, я думал, что производительность лучше всего улучшить путем распараллеливания максимально возможного фрагмента кода (например, самого внешнего цикла во вложенных циклах). cmo
Это правда, но с использованиемomp forля @ в цикле for требуются быстрые итераторы с произвольным доступом (например, которые работают в постоянное время). Насколько я знаю, std :: map вообще не предоставляет итератор произвольного доступа, и вы должны имитировать его. Hristo Iliev
Да, это то, что я пытался сделать в своем «предложенном решении», создав обычный массив (с произвольным доступом), а затем зацикливая его вместо карты напрямую. Я просто обеспокоен тем, что ваш метод создает слишком много накладных расходов (управление потоками на каждой итерации). cmo
OpenMP не создает отдельный поток для каждой задачи. Напротив, задачи помещаются в «мешок», а затем каждый поток крадет задачу. Исследования моих коллег показывают, что издержки практически ничтожны, а кодирование значительно упрощено. Я не пытаюсь убедить вас использовать задачи - просто попробуйте и посмотрите, какая из них быстрее, а какая требует больше программирования. Hristo Iliev

Похожие вопросы