由于某些怪异的原因,下面这段C++代码表现的异乎寻常—-当这段代码作用于有序数据时其速度可以提高将近6倍,这真是令人惊奇。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #include
#include
int _tmain ( int argc , _TCHAR * argv [])
{
const unsigned arraySize = 32768;
int data[arraySize];
for ( unsigned c = 0; c < arraySize; ++c)
data[c] = std:: rand () % 256;
std::sort(data, data + arraySize);
clock_t start = clock ();
long long sum = 0;
for ( unsigned i = 0; i < 100000; ++i){
for ( unsigned c = 0; c < arraySize; ++c){
if (data[c] >= 128)
sum += data[c];
}
}
double eclapsedTime = static_cast < double >( clock () - start) / CLOCKS_PER_SEC;
std::cout << eclapsedTime << std::endl;
std::cout << "sum = " << sum << std::endl;
return 0;
}
|
- 如果把 std::sort(data, data+arraySize) 去掉,这段代码耗时11.54秒。
- 对于有序数据,这段代码耗时1.93秒
起初我以为这可能是某一种语言或某一个编译器发生的异常的事件,后来我在java语言写了个例子,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | import java.util.Arrays;
import java.util.Random;
public class Test_Sorted_UnSorted_Array {
public static void main(String[] args) {
int arraySize = 32768 ;
int data[] = new int [arraySize];
Random rnd = new Random( 0 );
data[c] = rnd.nextInt()% 256 ;
Arrays. sort(data);
long start = System. nanoTime();
long sum = 0 ;
for ( int i= 0 ; i< 100000 ; ++i){
if (data[c] >= 128 )
sum += data[c];
}
}
System. out.println((System. nanoTime() - start) / 1000000000.0 );
System. out.println( "sum = " + sum);
}
}
|
上述例子运行结果和前面C++例子运行的结果差异,虽然没有C++中那么大,但是也有几分相似。
对于上面的问题,我首先想的原因是排序可能会导致数据有缓存,但是转念一想之前原因有点不切实际,因为上面的数组都是刚刚生成的,所以我的问题是:
- 上述代码运行时到底发生了什么?
- 为什么运行排好序的数组会比乱序数组快?
- 上述代码求和都是独立的,而顺序不应该会产生影响。
你是分支预测(branch prediction )失败的受害者。
什么是分支预测?
考虑一个铁路枢纽:
Imageby Mecanismo, via Wikimedia Commons. Used under theCC-By-SA 3.0license.
|