下面這個代碼用兩個雙層循環遍歷了一個二維數組里所有的元素,以我自己機器的測試 上面那個循環耗時基本為下面的一半,兩個循環的時間復雜度相同,為什么會有這么大的差別?
首先要明白的是不管是幾維數組,他們都是用一塊地址連續的內存來存儲所有的元素,而內存布局的順序是一整行接着下一個整行排列,第一個循環是一行一行訪問,所以從內存上看是順序的遍歷了這塊內存,每次讀取的位置都在上一次的附近,所以cache命中率高。第二個循環是一列一列訪問,可以說訪問的元素都不是連續的內存訪問(相隔了一行的大小),從而降低了cache的命中率。
cache的命中率對多層循環的影響是最明顯的,因此在設計循環邏輯的時候,如果有某個數據結構需要多次訪問,盡量讓其全部在最里層中完成訪問,提高cache對其的命中率。
#include <stdio.h> #include <stdlib.h> int main() { int hang = 1024*8; int lie = 1024*8; int c = 0; int **arr = (int **)malloc(sizeof(int*) * lie); for(c = 0; c < lie; c++) { arr[c] = (int*)malloc(sizeof(int) * hang); } struct timeval time1, time2; int i, j; gettimeofday(&time1, 0); for(j = 0; j < lie; j++) { for(i = 0; i < hang; i++) { arr[j][i] ++; } } gettimeofday(&time2, 0); printf("time %f\n", (double)(time2.tv_sec-time1.tv_sec) + (double)(time2.tv_usec-time1.tv_usec) /1000000); gettimeofday(&time1, 0); for(i = 0; i < hang; i++) { for(j = 0; j < lie; j++) { arr[j][i] ++; } } gettimeofday(&time2, 0); printf("time %f\n", (double)(time2.tv_sec-time1.tv_sec) + (double)(time2.tv_usec-time1.tv_usec) /1000000); return 0; }