C++
儘管使用了更多執行緒,為什麼我的程序變慢了?
我是執行緒新手,我想通過一個簡單的任務測試我新獲得的技能,使用多個執行緒創建圖像,有趣的是,在單個執行緒上,程序執行速度比使用 4 個執行緒(哪個我相信這是我最有效的並行執行緒執行能力)我有一個 i3 處理器,使用 ubuntu 17,我的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++)。
互斥鎖是一個紅鯡魚——它是函式的本地,因此它實際上並沒有鎖定任何東西,因為最終每個執行緒都有一個單獨的互斥鎖。為了真正鎖定,您需要將 mutex 變數移出 create_image。
但是,對圖像的寫入是獨立的,因此實際上不需要鎖定。也就是說,由於對 create_image 的每次呼叫都是針對單獨的區域,因此寫入不會重疊。您保證將通過加入執行緒等待其完成來記錄更改。
問題實際上是 rand()。根據我的測試,它有自己的內部互斥鎖,這導致了所有的減速。從 rand() 更改為 rand_r(&seed) 會有所不同。使用的執行緒越多,鎖定成本就越高(每次呼叫),因此您會看到速度變慢。
話雖如此,在我的 CPU 上,PNG 的創建是該程序的主要成本。在不編寫 PNG 圖像的情況下,程序在 2 秒(單執行緒)內執行,並且幾乎與使用的核心數量呈線性關係。寫入PNG圖像時,時間會跳到8s以上,因此寫入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; }