C++

儘管使用了更多執行緒,為什麼我的程序變慢了?

  • May 20, 2018

我是執行緒新手,我想通過一個簡單的任務測試我新獲得的技能,使用多個執行緒創建圖像,有趣的是,在單個執行緒上,程序執行速度比使用 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;
}

引用自:https://unix.stackexchange.com/questions/444653