より多くのスレッドを使用してもプログラムが遅くなるのはなぜですか? [閉鎖]

より多くのスレッドを使用してもプログラムが遅くなるのはなぜですか? [閉鎖]

私はここで初めてです。、私は以下を使用して画像を作成する簡単な作業で、新しく習得したスキルをテストしたいと思いました。マルチスレッド、興味深い部分は、シングルスレッドでは、4つのスレッドを使用するよりもプログラムが速く実行されます。(私はこれが私の最も効率的な並列スレッド機能だと思います。)私はubuntu 17を使用するi3プロセッサを持っていますstd::thread::hardware_concurrency は 4 です。。私のコード:

#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <png++/png.hpp>
#include <time.h>

std::vector<int> bounds(int max, int parts)
{
    std::vector<int> interval;
    int gap = max / parts;
    int left = max % parts;
    int nr1 = 0;
    int nr2;

    interval.push_back(nr1);
    for (int i = 0; i < parts; i++)
    {
        nr2 = nr1 + gap;
        if (i == parts - 1)
            nr2 += left;
        nr1 = nr2;
        interval.push_back(nr2);
    }
    return interval;
}

void create_image(png::image<png::rgb_pixel> &image, int start, int end)
{
    std::mutex my_mutex;
    std::lock_guard<std::mutex> locker(my_mutex);
    srand(time(NULL));
    for (int i = start; i < end; i++)
        for (int j = 0; j < image.get_height(); j++)
            image[i][j] = png::rgb_pixel(rand() % 256, 0, rand() % 256);
}

int main()
{
    png::image<png::rgb_pixel> png_image(6000, 6000);                  //Creating Image
    int parts = 1;                                                     //amount of parallel threads
    std::vector<int> my_vector = bounds(png_image.get_width(), parts); //interval vector
    std::vector<std::thread> workers;                                  //threads

    time_t start, end;
    time(&start); //measuring time
    for (int i = 0; i < parts - 1; i++)
    {
        workers.push_back(std::thread(create_image, std::ref(png_image), my_vector[i], my_vector[i + 1]));
    }
    for (int i = 0; i < parts - 1; i++)
        workers[i].join();

    create_image(png_image, my_vector[parts - 1], my_vector[parts]);

    png_image.write("test.png");
    time(&end);
    std::cout << (end - start) << " seconds\n";

    return 0;
}

ビルドするにはg++ file.cpp -o test -lpng -pthread:PNG++)。

ベストアンサー1

ミューテックスは赤ニシンです。これは関数にローカルなので、各スレッドが別々のミューテックスで終わるので、実際には何もロックしません。実際にロックするには、create_imageでミューテックス変数を移動する必要があります。

しかし、画像への書き込みは独立しているので、実際にロックは必要ありません。つまり、create_imageへの各呼び出しは別々の領域へのものであるため、書き込みは重複しません。スレッドに参加して完了するまで待つことで、変更が記録されることを確認できます。

問題は実際にはrand()です。私のテストでは、独自の内部ミューテックスがあり、すべての速度が低下します。 rand() から rand_r(&seed) に変更すると、大きな違いが発生します。使用するスレッドが多ければ多いほど、(呼出あたり)ロックのコストが高くなるため、速度が遅くなることがわかります。

しかし、私のCPUでは、PNG生成はプログラムの主なコストです。 PNGイメージを作成しないと、プログラムは2秒以内に実行され(シングルスレッド)、使用されているコアの数に応じてほぼ直線的に拡張されます。 PNG画像を作成すると時間が8秒以上になるため、画像を作成するよりもPNG画像を作成するのに時間がかかります。

これが私が思いついたものです:

#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <png++/png.hpp>
#include <time.h>

std::vector<int> bounds(int max, int parts)
{
    std::vector<int> interval;
    int gap = max / parts;
    int left = max % parts;
    int nr1 = 0;
    int nr2;

    interval.push_back(nr1);
    for (int i = 0; i < parts; i++)
    {
        nr2 = nr1 + gap;
        if (i == parts - 1)
            nr2 += left;
        nr1 = nr2;
        interval.push_back(nr2);
    }
    return interval;
}

void create_image(png::image<png::rgb_pixel> &image, int start, int end)
{
    unsigned int seed = time(NULL);
    for (int i = start; i < end; i++)
        for (int j = 0; j < image.get_height(); j++)
            image[i][j] = png::rgb_pixel(rand_r(&seed) % 256, 0, rand_r(&seed) % 256);
}

int main()
{
    png::image<png::rgb_pixel> png_image(6000, 6000);                  //Creating Image
    int parts = 1;                                                     //amount of parallel threads
    std::vector<int> my_vector = bounds(png_image.get_width(), parts); //interval vector
    std::vector<std::thread> workers;                                  //threads

    time_t start, end;
    time(&start); //measuring time
    for (int i = 0; i < parts; i++)
    {
        workers.push_back(std::thread(create_image, std::ref(png_image), my_vector[i], my_vector[i + 1]));
    }
    for (int i = 0; i < parts; i++)
        workers[i].join();

    png_image.write("test.png");
    time(&end);
    std::cout << (end - start) << " seconds\n";

    return 0;
}

おすすめ記事