2016-11-04 64 views
2

全部: 我有兩段代碼。第一個是:爲什麼這個C++代碼不是更快?

#include <iostream> 

using namespace std; 

static constexpr long long n = 1000000000; 

int main() { 
    int sum = 0; 
    int* a = new int[n]; 
    int* b = new int[n]; 

    for (long long i=0; i<n; i++) { 
    a[i] = static_cast<int>(i); 
    } 

    for (long long i=0; i<n; i++) { 
    sum *= a[i]; 
    sum += a[i]; 
    } 

    for (long long i=0; i<n; i++) { 
    b[i] = static_cast<int>(i); 
    } 

    for (long long i=0; i<n; i++) { 
    sum *= b[i]; 
    sum += b[i]; 
    } 

    cout<<sum<<endl; 
} 

第二個是:

#include <iostream> 

using namespace std; 

constexpr long long n = 1000000000; 

int main() { 
    int* a = new int[n]; 
    int* b = new int[n]; 
    int sum = 0; 

    for (long long i=0; i<n; i++) { 
    a[i] = static_cast<int>(i); 
    b[i] = static_cast<int>(i); 
    } 

    for (long long i=0; i<n; i++) { 
    sum *= a[i]; 
    sum += a[i]; 
    sum *= b[i]; 
    sum += b[i]; 
    } 

    cout<<sum<<endl; 
} 

我認爲第一方案應比第二快的多,因爲它更多的緩存友好。然而,事實是第二個是更快的垃圾。在我的服務器上,第一個需要23秒,而第二個需要20秒,有人可以解釋這一點嗎?

+5

不過,它看起來像運行1000000000循環兩次而不是四次更快。我想知道爲什麼。如果我錯了,用鐵鏟打我,但我認爲這是不言自明的。 – Steeve

+3

由於您正在生成大量的整數溢出,無論如何,您的程序完全未定義行爲。 –

+5

沒有足夠的信息。你使用什麼編譯器標誌?什麼是所有的靜態鑄造?儘管如此,這可能是目前最高的C++問題的克隆:http://stackoverflow.com/questions/11227809/why-is-it-faster-to-process-a-sorted-array-than-an-unsorted -array –

回答

3

你沒有看到緩存友好的優勢,因爲訪問模式仍是即使在您預測要慢一些的版本太簡單了。

兩個(或更多)直線輸入的併發流是什麼現代CPU可以檢測和流分成L1提前被需要它。

它也可以允許多個SDRAM銀行同時進行有用的工作。如果你使用的是Linux,你不會對此有太多的控制,因爲頁面是隨機映射的(我認爲這仍然是真的?),但你可以嘗試使用mmap()MAP_HUGETLB參數分配內存,然後嘗試使用不同的偏移量分配的開始。

如果你想看到一個緩存友好的訂單,你應該有不同的訪問模式在二維數組也許嘗試安排您計算的優勢。

+0

是的,你是對的。我嘗試了二維數組的方式,它更快。 –

-1

的第一段代碼,您使用 4迴路來完成任務。

for (long long i=0; i<n; i++) { 
    a[i] = static_cast<int>(i); 
    } 

    for (long long i=0; i<n; i++) { 
    sum *= a[i]; 
    sum += a[i]; 
    } 

    for (long long i=0; i<n; i++) { 
    b[i] = static_cast<int>(i); 
    } 

    for (long long i=0; i<n; i++) { 
    sum *= b[i]; 
    sum += b[i]; 
    } 

而在第二個你只使用2個循環來完成任務。

for (long long i=0; i<n; i++) { 
    a[i] = static_cast<int>(i); 
    b[i] = static_cast<int>(i); 
    } 

    for (long long i=0; i<n; i++) { 
    sum *= a[i]; 
    sum += a[i]; 
    sum *= b[i]; 
    sum += b[i]; 
    } 

您提供的第二段代碼中發生的迭代次數要少得多。

+0

因此,除了測試的給定結果之外,是什麼讓您認爲迭代次數總是比緩存友好性重要?這是這個問題的基本思想。 – stefaanv

+0

井OP認爲第一個會更快,因爲操作會更多的緩存局部導致更少的失誤,這可能會使循環更快,並使迭代更少。 – Hayt

+0

即使有更多的循環,操作的次數也大致相同,唯一的區別在於'i'的增量和與'n'的比較次數。我認爲這不足以證明性能上的差異,也是因爲在編譯時'n'知道編譯器可以執行各種優化 – alessandrolenzi

2

緩存在你的例子中並不扮演重要角色。線性訪問數組munch比緩存大,並且在訪問之間幾乎不計算總是受限於內存帶而不是緩存。他們根本沒有足夠的時間通過預取來填滿。

你所測試的是你的編譯器的聰明才智,你的四/二回路優化成一個或他的聰明,讓你在做什麼線索,只是打印結果。