Чтение / запись в общий вектор в OpenMP замедляют работу программы - PullRequest
0 голосов
/ 21 октября 2019

Я пытаюсь использовать OpenMP для вектора шарда. В моих реальных кодах у меня есть вектор, в котором хранятся массивы, и я хочу использовать OpenMP для ускорения одного цикла for, где мне нужно получить доступ ко всем этим элементам внутри вектора и вычислить взаимодействия со всеми другими элементами в пределах диапазона отсечки. Это означает, что в разных порциях вектора вычисление взаимодействия является своего рода независимым. И вычисления являются однонаправленными и периодическими, начинаются с первого элемента и заканчиваются последним элементом, взаимодействующим с первыми несколькими элементами. Я просто хочу использовать два потока для проверки осуществимости, и я делю рабочую нагрузку на две части, которые, я думаю, они независимы друг от друга.

Но время моделирования с одним ядром: реальный 0m2.417s пользователь 0m2.149s sys 0m0.011s

с многопоточностью это: реальный 0m4.490s пользователь 0m8.371s sys 0m0.024s

ОБНОВЛЕНИЕ

Спасибо, что люди уже дали мне несколько советов, которые я очень ценю. Я хочу дать более подробную информацию о моем коде: таким образом, у вектора есть 100 элементов, каждый элемент будет выполнять вычисления с правыми соседними девятью элементами. Это непросто, потому что на самом деле эту работу можно разделить на 10 видов независимой работы, поэтому я наивно думаю, что это подходит для параллельных вычислений, но если потоки работают не так хорошо, как организовано, вполне возможно, что произойдет гонка,Итак, как я могу определить рабочую нагрузку для использования OpenMP, чтобы убедиться, что разные потоки читают / записывают разные части вектора?

#include <stdio.h>
#include <omp.h> 
#include <vector>
#include <array>
#include <iostream>
using namespace std;

auto k = 50000;
auto cutOff = k/10;

void testFunc(vector<int> &positions){
#pragma omp parallel for num_threads(2) schedule(static, k/2)
    for (int i = 0; i< k ; i++){
        for (int j = i; j<i+cutOff; j++){
            j=(j<=k?j:j-k);
                positions[i]+=1;
                positions[j]-=1;
        }
    }
}

int main()
{
    vector<int> pos;
    pos.resize(k);
    for (int i = 0; i<pos.size(); i++){
            pos[i]=rand() % 100;
        }

    printf("first value = %d\n", pos[0]);
    testFunc(pos);
    printf("last value = %d\n", pos[0]);
}

1 Ответ

0 голосов
/ 21 октября 2019

Как вы правильно заметили, работу можно разделить на независимые куски или «секции», например, так:

void testFunc(vector<int> &positions){
    int numSections = cutOff;
    for (int section = 0; section < numSections; ++section) {
#pragma omp parallel for schedule(static)
        for (int i = section; i < k ; i += cutOff) {
            for (int offset = 0; offset < cutOff; ++offset) {
                int j = i + offset;
                if (j >= k)
                    j -= k;
                positions[i] += 1;
                positions[j] -= 1;
            }
        }
    }
}

https://godbolt.org/z/qdC0Rw

Обратите внимание, что это работает только правильноесли k на самом деле делится на cutOff! (Рассмотрим k = 11 и cutOff = 10.)

Похоже, что при запуске большого количества параллельных секций много работы, если cutOff велико (например, если это 10% от k), но этобольше из-за того, что сам алгоритм является квадратичным (он изменяет 2 * k * cutOff = 0.2 * k * k элементов). Так что если ваш k большой, распараллеливание все равно должно стоить.

...