C++二维数组按行遍历和按列遍历的区别
按行遍歷的效率更高。(重要前提假設:數組,按行儲存;對于clickhouse-client-cpp,由于數據是按列存儲的,按列遍歷的效率更好)
數組在內存中是按行儲存的,按行遍歷時可以由指向數組第一個數的指針一直往下走,就可以遍歷完整個數組,而按列遍歷則要獲得指向每一列的第一行的元素的指針,然后每次將指針指下一行,但是指針的尋址很快,所以不會有明顯的區別。
按行遍歷比按列遍歷效率高具體體現在以下幾點
1、CPU高速緩存
計算機存在Cache機制,當處理器發出內存訪問請求時,會先查看緩存內是否有請求數據。如果存在,則不經訪問內存直接返回該數據;如果不存在,則要先把內存中的相應數據載入緩存,再將其返回處理器。
緩存從內存中抓取一般都是整個數據塊,所以它的物理內存是連續的,幾乎都是同行不同列的,而如果內循環以列的方式進行遍歷的話,將會使整個緩存塊無法被利用,而不得不從內存中讀取數據,而從內存讀取速度是遠遠小于從緩存中讀取數據的。
2、分頁調度
物理內存是以頁的方式進行劃分的,當一個二維數組很大是如 int[128][1024],假設一頁的內存為4096個字節,而每一行正好占據內存的一頁(int 存儲是4個字節),如果以列的形式進行遍歷,就會發生128*1024次的頁面調度,而如果以行遍歷則只有128次頁面調度,而頁面調度是有時間消耗的,因而調度次數越多,遍歷的時間就越長。
示例:
1.程序:
#include<cstdio> #include<cstdlib> #include<sys/time.h> #include<sys/resource.h>// 從進行開始執行到完成所經歷的墻上時鐘時間(wall clock)時間, // 包括其他進程使用的時間片(time slice)和本進程耗費在阻塞(如等待I/O操作完成)上的時間// CPU時間是指進程占用CPU的時間,進程阻塞的時間則不會計入CPU時間 void gettime(double *cpu) {struct rusage ru;if(cpu != NULL){getrusage(RUSAGE_SELF, &ru);*cpu = ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec * 1e-6;} }int main(int argc,char* argv[]) {int count = 20000;double cpu0,cpu1,cpu2;int* arr = (int*)malloc(sizeof(int) * count * count);int i,j;gettime(&cpu0);// 按行遍歷二維數組for(i=0;i<count;i++){for(j=0;j<count;j++){arr[i * count + j]=1;//printf("%d-%d ",i,j);}}// printf("\n");gettime(&cpu1);// 按列遍歷二維數組for(i=0;i<count;i++){for(j=0;j<count;j++){arr[j * count + i]=1;// printf("%d-%d ",j,i);}}// printf("\n");gettime(&cpu2);printf("按行遍歷二維數組CPU時間差:%lf\n",cpu1-cpu0);printf("按列遍歷二維數組CPU時間差:%lf\n",cpu2-cpu1);return 0; }測試機器:
處理器:Apple M1
內存:8g
2.結果:
count=1000?
?
count=5000?
?
count=10000?
?
count=20000?
?
3.說明
第一個for循環按行訪問二維數組(第一行第一個、第一行第二個……第二行第一個……),第二個for循環按列訪問二維數組(第一行第一個、第二行第一個……第一行第二個……),分別計算兩個for循環的時間差
由實驗結果可以看出,隨著數組數據量的增大,兩種訪問二維數組的方式的速度相差越來越大
4.原理分析
二維數組的內存地址是連續的,當前行的尾與下一行的頭相鄰
現代計算機,在CPU與內存之間還有一種存儲機制,那就是CPU緩存(cache)。CPU緩存的容量比內存小的多但是交換速度卻比內存要快得多。緩存的出現主要是為了解決CPU運算速度與內存讀寫速度不匹配的矛盾,因為CPU運算速度要比內存讀寫速度快很多,這樣會使CPU花費很長時間等待數據到來或把數據寫入內存。
訪問數組元素時,CPU不會每次只從內存中讀取一個元素,而是讀取一個區域的元素。假設二維數組的大小為(10 x 10),訪問第一個元素時,CPU也會讀取它的相鄰元素,因為這個數組比較小,CPU一次就可以把所有元素緩存,因此無論是按行訪問數組還是按列訪問數組,CPU訪問主存的數量都相同。隨著數組元素越來越多,CPU緩存一次只能讀取數組不到一行的數據,因此按列訪問元素時每訪問一個元素都要訪問內存,因此速度就會慢很多。
對于clickhouse-client-cpp,由于數據是按列存儲的,按列遍歷的效率更好:
全市場1分鐘行情數據,按行遍歷3s,按列遍歷則只需要1.8s
總結
以上是生活随笔為你收集整理的C++二维数组按行遍历和按列遍历的区别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CentOS 7升级gcc 8.3.1
- 下一篇: C++ std::condition_v