簡體   English   中英

為什么我不能通過在C ++ 11中運行多個線程來獲得任何性能改進?

[英]Why can't I get any performance improvements by running multiple threads in C++11?

我有以下測試程序,其中包含一個簡單的函數,可以找到我嘗試在多個線程中運行的素數(僅作為示例)。

#include <cstdio>
#include <iostream>
#include <ctime>
#include <thread>

void primefinder(void)
{
   int n = 300000;

   int i, j;
   int lastprime = 0;
   for(i = 2; i <= n; i++) {
      for(j = 2; j <= i; j++) {
           if((i % j) == 0) {
               if(i == j)
                   lastprime = i;
               else {
                   break;
               }
           }
      }
   }

   std::cout << "Prime: " << lastprime << std::endl;
}

int main(void)
{
   std::clock_t start;
   start = std::clock();

   std::thread t1(primefinder);
   t1.join();

   std::cout << "Time: " << (std::clock() - start) / (double)(CLOCKS_PER_SEC / 1000) << " ms" << std::endl;

   start = std::clock();

   std::thread t2(primefinder);
   std::thread t3(primefinder);
   t2.join();
   t3.join();

   std::cout << "Time: " << (std::clock() - start) / (double)(CLOCKS_PER_SEC / 1000) << " ms" << std::endl;
   return 0;
}

如圖所示,我在1個線程中運行一次該函數,然后在2個不同的線程中運行一次。 我用g ++使用-O3和-pthread編譯它。 我在Linux Mint 18上運行它。我有一個Core i5-4670。 我知道它歸結為操作系統,但我非常希望這些線程在某種程度上並行運行。 當我運行程序時,top使用1個線程時顯示100%CPU,使用2個線程時顯示200%CPU。 盡管如此,第二次運行幾乎只需要兩倍的時間。

運行程序時,CPU不執行任何其他操作。 為什么不並行執行?

編輯:我知道兩個線程都在做同樣的事情。 我選擇了primerfinder函數只是作為一個令人尷尬的並行的例子,因此當我在多個線程中運行它時,它應該花費實時的時間。

使用std :: clock來計算c ++中的並行程序非常具有欺騙性。 在計划計划時我們關心的時間有兩種:掛起時間和CPU時間。 壁掛時間是我們都習慣的(想想牆上的時鍾)。 CPU時間本質上是程序使用的cpu周期數。 std :: clock返回cpu時間(這就是你除以CLOCKS_PER_SEC的原因)並且當有一個執行線程時,cpu time只等於wall time。 如果一個程序可以100%並行運行(比如你的),那么cpu time =(線程數)*(wall time)。 因此,看到幾乎兩倍的長度正是您所期望的。

為了測量牆壁時間(這是你想要做的),我不知道如何使用STL來做到這一點。 您可以使用OpenMP或Boost進行測量。

omp_get_wtime()

升壓定時器

由於您使用的是Linux,因此您使用的g ++版本很可能內置了openmp支持。

#include <omp.h>

const double startTime = omp_get_wtime();
..... //Work goes here

const double time = omp_get_wtime() - startTime;

您必須使用-fopenmp進行編譯

編輯:

正如johnbakers指出的那樣,計時庫確實有一個掛鍾

#include <chrono>

auto start = std::chrono::system_clock::now();
.... //Do some work

auto end = std::chrono::system_clock::now();
std::chrono::duration<double> diff = end - start;
std::cout << "Time: " << diff.count() << "(s)" << std::end;

輸出與升壓計時器:

Boost: 121.685972s wall, 724.940000s user + 67.660000s system = 792.600000s CPU  (651.3%)
Chrono: 121.683(s)

您的設計中存在一個非常基本的問題,這就解釋了為什么您沒有看到線程帶來的任何好處。

當你遇到像這樣的搜索問題並想要通過並行化加速時,通常會使用分而治之 你需要以某種方式分配工作,以便例如第一個線程將執行工作的前半部分,第二個線程將執行工作的后半部分。

在你的代碼中,兩個線程都調用完全相同的函數並且它們不進行通信 - 它們各自復制了另一個人的工作!

在某些問題上,很容易將工作分開。 例如,如果您正在使用SAT求解器 ,則在兩個線程之間划分工作的一種方法是選擇變量x_1 ,並且假設第一個線程將假設x_1 = true並檢查公式是否可滿足,並且第二個線程將假設x_1 = false並檢查公式是否可滿足。 然后,當它們都加入時,您將知道整體公式是否可滿足,並且不需要互斥或互連通信。

在你的素數問題中,它有點復雜。 你可以嘗試做類似的事情,第一個線程只考慮以1, 3, 5結尾的候選者,第二個線程認為候選者以7, 9結尾。 為了獲得最佳性能,您可能希望使用類似“ Eratosthenes'Sieve”的東西,我認為並行化會更難。 (你可以使用原子數組嗎?)

有許多可能的原因代碼不平行。

在舊的日子里,操作系統將以循環法或優先級方法運行多個可執行文件。 因此,一個執行線程可以運行幾毫秒,然后與另一個執行線程交換。 這將給出執行線程並行運行的外觀

當一個線程等待資源並且資源不可用時,也會發生交換執行線程。

在具有多個處理器或核心的現代計算機中,該技術仍然是相同的。 操作系統有另一個可以將任務委派給的處理器。 核心時間很寶貴。 操作系統不太可能停止多核上的所有正在運行的任務,因此您的線程可以並行執行。 這可能意味着操作系統必須等待一個處理器完成,以便您的線程可以同時執行。 最有可能不會發生。

但是,許多操作系統都具有可以設置的屬性,以告訴它們為線程提供對一個或多個內核的獨占訪問權限。 由於這不是標准的C ++功能,並且操作系統不完全相同,因此您必須查找API或任何編譯器特定的支持。

編輯1:中斷和其他任務
請記住,您的平台並非專門運行您的程序。 其他任務潛伏着,並且可能在程序運行時執行。 一些例子包括:病毒檢查程序,ping互聯網的東西和音樂播放器(至少在我的機器上)。

這些應用程序和中斷可能會導致操作系統在同一處理器上與您的線程進行循環播放,而不是並行播放。 一旦情況是將音樂播放器放在一個處理器上,為什么你的程序在另一個處理器上運行。

看一下std::chrono命名空間 它提供了許多用於測量時間的C ++ 11實用程序,它們優於目前為止的每個建議。

例如,您可以時鍾讀數轉換為掛起時間。

時序編程代碼並非易事,但這些工具確實使這些工具更容易探索。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM