2016-11-04 65 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比缓存大,并且在访问之间几乎不计算总是受限于内存带而不是缓存。他们根本没有足够的时间通过预取来填满。

你所测试的是你的编译器的聪明才智,你的四/二回路优化成一个或他的聪明,让你在做什么线索,只是打印结果。