Это нормально, что мой код работает быстрее без многопоточности o я делаю что-то не так? - PullRequest
1 голос
/ 03 апреля 2020

Я пытаюсь оптимизировать свой код, используя многопоточность, и дело не только в том, что программа не имеет двойной скорости, как это предполагается в этом двухъядерном компьютере, она НАМНОГО МЕДЛЕННА. И я просто хочу знать, делаю ли я что-то неправильно или это нормально, что в этом случае использование многопоточности не помогает. Я делаю это воссоздание того, как я использовал многопоточность, и на моем компьютере параллельные версии занимают в 4 раза больше времени по сравнению с обычной версией:

#include <iostream>
#include <random>
#include <thread>
#include <chrono>

using namespace std;

default_random_engine ran;
inline bool get(){
    return ran() % 3;
}

void normal_serie(unsigned repetitions, unsigned &result){
    for (unsigned i = 0; i < repetitions; ++i)
        result += get();
}

unsigned parallel_series(unsigned repetitions){
    const unsigned hardware_threads = std::thread::hardware_concurrency();
    cout << "Threads in this computer: " << hardware_threads << endl;
    const unsigned threads_number = (hardware_threads != 0) ? hardware_threads : 2;
    const unsigned its_per_thread = repetitions / threads_number;
    unsigned *results = new unsigned[threads_number]();
    std::thread *threads = new std::thread[threads_number - 1];

    for (unsigned i = 0; i < threads_number - 1; ++i)
        threads[i] = std::thread(normal_serie, its_per_thread, std::ref(results[i]));
    normal_serie(its_per_thread, results[threads_number - 1]);
    for (unsigned i = 0; i < threads_number - 1; ++i)
        threads[i].join();

    auto result = std::accumulate(results, results + threads_number, 0);
    delete[] results;
    delete[] threads;
    return result;
}

int main()
{
    constexpr unsigned repetitions = 100000000;
    auto to = std::chrono::high_resolution_clock::now();
    cout << parallel_series(repetitions) << endl;
    auto tf = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(tf - to).count();
    cout << "Parallel duration: " << duration << "ms" << endl;

    to = std::chrono::high_resolution_clock::now();
    unsigned r = 0;
    normal_serie(repetitions, r);
    cout << r << endl;
    tf = std::chrono::high_resolution_clock::now();
    duration = std::chrono::duration_cast<std::chrono::milliseconds>(tf - to).count();
    cout << "Normal duration: " << duration << "ms" << endl;
    return 0;
}

Вещи, которые я уже знаю, но я не знал t, чтобы сделать этот код короче:

Я должен установить max_iterations_per_thread, потому что вы не хотите делать 10 итераций на поток, но в этом случае мы делаем один миллиард итераций, так что это не произойдет. Количество итераций должно делиться на количество или потоки, иначе код не будет работать эффективно.

Это вывод, который я получаю на моем компьютере:

Threads in this computer: 2
66665160
Parallel duration: 4545ms
66664432
Normal duration: 1019ms

(Решено частично с внесением этих изменений:)

inline bool get(default_random_engine &ran){
    return ran() % 3;
}

void normal_serie(unsigned repetitions, unsigned &result){
    default_random_engine eng;
    unsigned saver_result = 0;
    for (unsigned i = 0; i < repetitions; ++i)
        saver_result += get(eng);
    result += saver_result;
}

Ответы [ 2 ]

3 голосов
/ 03 апреля 2020

Все ваши потоки спотыкаются друг о друга, борясь за доступ к ran, который может выполнять только одну операцию за раз, потому что он имеет только одно состояние, и каждая операция продвигает свое состояние. Бессмысленно выполнять параллельные операции, если в подавляющем большинстве каждой операции есть дроссельная точка, которая не может поддерживать какой-либо параллелизм.

1 голос
/ 03 апреля 2020

Все элементы results могут совместно использовать строку кэша, что означает, что происходит много межъядерного взаимодействия.

Попробуйте изменить normal_serie для накопления в локальной переменной и только записи это к results в конце.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...