Общие векторы в OpenMP

Я пытаюсь parallize программы я использую и встал следующий вопрос. Потеряю ли я производительность, если нескольким потокам нужно читать / писать на одном векторе, но разные элементы вектора ? У меня такое чувство, вот почему моя программа вряд ли станет быстрее на parallizing его. Возьмите следующий код:

#include <vector> 

int main(){

    vector<double> numbers;
    vector<double> results(10);
    double x;

    //write 10 values in vector numbers
    for (int i =0; i<10; i++){
        numbers.push_back(cos(i));  
    } 

#pragma omp parallel for 
    private(x) 
    shared(numbers, results)
        for(int j = 0;  j < 10;  j++){

            x  =  2 * numbers[j]  +  5;  
#pragma omp critical  // do I need this ?
            {
                results[j]  =  x;     
            }
        }

    return 0;

}

очевидно, что фактическая программа выполняет гораздо более дорогие операции, но этот пример должен только объясните мой вопрос. Так может цикл for можно сделать быстро и полностью параллельно или разные потоки должны ждать друг друга, потому что только один поток за раз может получить доступ к номеру вектора, например, хотя все они читают разные элементы вектора ?

тот же вопрос с операцией записи: нужна ли мне критическая ПРАГМА или это не проблема, так как каждый поток записывает в другой элемент результатов вектора ? Я доволен каждой помощью, которую я могу получить, а также было бы хорошо знать, есть ли лучший способ сделать это (возможно, вообще не использовать векторы, а простые массивы и указатели и т. д. ?) Я также читаю, что векторы не являются потокобезопасными в некоторых случаях, и рекомендуется использовать указатель:OpenMP и STL вектор

большое спасибо за вашу помощь!

2 ответов


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

Если вы не изменяете размер своего массива, то у меня никогда не было проблем с параллельной записью чтения в вектор (очевидно, пока я не пишу дважды тот же элемент)

Что касается отсутствия повышения производительности, критический раздел openmp замедлит вашу программу, вероятно, так же, как просто с помощью 1 потока (в зависимости от того, сколько на самом деле сделано за пределами этого критического раздела)

вы можете удалить оператор критического раздела (с учетом приведенных выше условий).


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

вы также можете играть со стратегией расписания, потому что, если доступ к памяти не является линейным (это в приведенном примере), потоки могут бороться за кэш (запись элементов в той же строке кэша). OTOH если количество элементов задано как в вашем случае, так и там нет ветвления в цикле (поэтому они будут выполняться примерно с той же скоростью), static, который является IIRC по умолчанию, должен работать лучше всего в любом случае.

(кстати, вы можете объявить x внутри цикла, чтобы избежать private(x) и shared директива подразумевается IIRC (я никогда не использовал ее).)