Многопоточность замедляет работу программы: нет ложного обмена, нет мьютекса, нет ошибок в кеше, нет малой рабочей нагрузки - PullRequest
0 голосов
/ 23 сентября 2018

Многопоточность замедляет мой код, хотя я обратил внимание на следующие сообщения:

Многопоточный GEMM медленнее однопоточного?

Почему эта OpenMP-программа работает медленнее, чем однопоточная?


Я думаю, что все меры предосторожности были соблюдены:

  1. Мой процессор4 ядра + гиперпоточность (8 эффективно), и я не запускаю более 4 потоков

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

  3. Записи в памяти являются последовательными,вероятность пропуска кэша очень мала.

  4. с использованием переменной tmp для последовательных операций вместо назначения значений непосредственно в массив.

  5. Сборка в режиме релиза, visual studio

  6. Критических точек между потоками нет (они не используют мьютексы и не обмениваются данными)

При измерении времени я включаю создание потока.Конечно, запуск 4 потоков не может быть таким дорогим?

1 поток: около 140 миллисекунд

4 потока: около 155 миллисекунд

Main:

struct MyStruct {
   double val = 0;
};


size_t numEntries = 100e4;
size_t numThreads = 4;
std::vector<MyStruct> arr;


void main(){
    arr.reserve(numEntries);
    for(size_t i=0; i<numEntries; ++i){
        MyStruct m{ i };
        arr.push_back(m);
    }

    //run several times 
    float avgTime=0;
    for(size_t n=0; n<100; ++n){
        launchThreads(avgTime);
        //space out to make avgTime more even:
        std::this_thread::sleep_for(std::chrono::milliseconds(10));

    }

    avgTime /= 100;

    std::cout << "finished in " << avgTime <<"milliseconds\n";
    system("pause");
}

Запуск и запуск потоков:

//ran by each thread
void threadWork(size_t threadId){
    size_t numPerThread = (numEntries+numThreads -1) / numThreads;

    size_t start_ix = threadId * numPerThread;

    size_t endIx;
    if (threadId == numThreads - 1) {
        endIx = numEntries-1;//we are the last thread
    }
    else {
        endIx = start_ix + numPerThread;
    }

    for(size_t i=5; i<endIx-5; ++i){
        double tmp = arr[i].val; 

        tmp += arr[i-1].val;
        tmp += arr[i-3].val;
        tmp += arr[i-4].val;
        tmp += arr[i-5].val;
        tmp += arr[i-2].val;

        tmp += arr[i+1].val;
        tmp += arr[i+3].val;
        tmp += arr[i+4].val;
        tmp += arr[i+5].val;
        tmp += arr[i+2].val;

        if(tmp > 0){ tmp *= 0.5f;}
        else{ tmp *= 0.3f; }

        arr[i].val = tmp;
    }
}//end()


//measures time
void launchThreads(float &avgTime){

    using namespace std::chrono;
    typedef std::chrono::milliseconds ms;

    high_resolution_clock::time_point t1 = high_resolution_clock::now();

    std::vector<std::thread> threads;
    for (int i = 0; i <numThreads; ++i) {
        std::thread t = std::thread(threadWork, i);
        threads.push_back(std::move(t));
    }

    for (size_t i = 0; i < numThreads; ++i) {
        threads[i].join();
    }
    high_resolution_clock::time_point t2 = high_resolution_clock::now();
    ms timespan = duration_cast<ms>(t2 - t1);
    avgTime += timespan.count();
}

1 Ответ

0 голосов
/ 23 сентября 2018

Ваша проблема в следующем:

for(size_t i=5; i<endIx-5; ++i){
           ^^^

Должно быть:

for(size_t i=start_ix + 5; i<endIx-5; ++i){
           ^^^^^^^^^^^^^^
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...