私はここで初めてです。糸、私は以下を使用して画像を作成する簡単な作業で、新しく習得したスキルをテストしたいと思いました。マルチスレッド、興味深い部分は、シングルスレッドでは、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;
}