for循环效率
2016-04-18 22:13
281 查看
《高质量程序设计语言》提到for循环遍历数组中“先行后列”和“先列后行”有不同的效率。这个勾起了我的兴趣,原文介绍的应该是针对二维数组及其以上的多维数组。效率不同的原因是不同的语言安排数组元素的存储空间的顺序不一样。比如C/C++语言按照“先行后列”的顺序安排数组元素的存储空间。Fortran语言按照“先列后行”的顺序安排数组元素的存储空间。会导致什么后果呢?
引用书中的例子来说明,假设二维数组num
[M],每一行数据刚好占据一页内存(4KB),且C/C++语言按照“先行后列”的顺序安排数组元素的存储空间,如下图所示:
我们来看看不同的循环遍历顺序需要多少次页面调度?
1、“先行后列”。从图中可以发现,一共需要进行12次页面调度。
2、“先列后行”。从图中可以发现,一共需要12 * 1024次页面调度。
这才是两种遍历顺序导致的效率不同的主要原因。
————————————————–分割线———————————————————
OK下面进行代码测试,测试平台是VS2015。测试情况分为四种:
1、创建一个二维数组,先进行“先行后列”后进行“先列后行”遍历。
2、创建一个二维数组,先进行“先列后行”后进行“先行后列”遍历。
3、创建一个二维数组,进行“先列后行”遍历。
4、创建一个二维数组,进行“先行后列”遍历。
代码如下
测试结果
测试情况1
测试情况2
测试情况3
测试情况4
结论(限于测试次数的原因,调度遍历方式对遍历时间的影响只作为观测结果)
调度遍历方式顺序一:“先行后列”-> “先列后行”;
调度遍历方式顺序二:“先列后行”-> “先行后列”;
1、当列数远大于行数时,“先行后列”的遍历时间最小。但在本次测试中发现是与调度遍历方式的顺序无关。
2、当行数远大于列数时,“先行后列”的遍历时间最小。调度顺序二明显使整体的遍历时间变小,但是增加了“先行后列”的遍历时间,减小了“先列后行”的遍历时间。
3、当行列数相等时,“先行后列”的遍历时间最小。调度顺序基本无影响。
4、当行列数都比较小时,遍历顺序基本无影响。
具体的解释可能与cache命中率有关,这里没有进行进一步的分析==
引用书中的例子来说明,假设二维数组num
[M],每一行数据刚好占据一页内存(4KB),且C/C++语言按照“先行后列”的顺序安排数组元素的存储空间,如下图所示:
我们来看看不同的循环遍历顺序需要多少次页面调度?
1、“先行后列”。从图中可以发现,一共需要进行12次页面调度。
2、“先列后行”。从图中可以发现,一共需要12 * 1024次页面调度。
这才是两种遍历顺序导致的效率不同的主要原因。
————————————————–分割线———————————————————
OK下面进行代码测试,测试平台是VS2015。测试情况分为四种:
1、创建一个二维数组,先进行“先行后列”后进行“先列后行”遍历。
2、创建一个二维数组,先进行“先列后行”后进行“先行后列”遍历。
3、创建一个二维数组,进行“先列后行”遍历。
4、创建一个二维数组,进行“先行后列”遍历。
代码如下
#include "stdafx.h" int main() { int N, M, i,j,k; int **num = NULL; DWORD start, end; while (fscanf_s(stdin, "%d%d", &N, &M) != EOF) { //创建二维数组 num = (int **)malloc(N*sizeof(int *)); if (NULL == num) { printf("malloc error\n"); return -1; } for (i = 0; i < N; i++) { num[i] = (int *)malloc(M*sizeof(int)); if (NULL == num[i]) { printf("malloc error\n"); k = i; goto error; } } //先行后列 start = GetTickCount(); for (i = 0; i < N; i++) for (j = 0; j < M; j++) num[i][j] = 1; end = GetTickCount(); printf("first row next colum: \n"); printf("N=%d, M=%d : %dms\n",N,M,end-start); //先列后行 start = GetTickCount(); for (i = 0; i < M; i++) for (j = 0; j < N; j++) num[j][i] = 1; end = GetTickCount(); printf("first colum next row: \n"); printf("N=%d, M=%d : %dms\n", N, M, end - start); //释放二维数组 for (i = 0; i < N; i++) free(num[i]); free(num); printf("\n"); } return 0; error: if (NULL != num) { for (i = 0; i < k; i++) { if (NULL != num[i]) free(num[i]); } free(num); } return -1; }
测试结果
测试情况1
测试情况2
测试情况3
测试情况4
结论(限于测试次数的原因,调度遍历方式对遍历时间的影响只作为观测结果)
调度遍历方式顺序一:“先行后列”-> “先列后行”;
调度遍历方式顺序二:“先列后行”-> “先行后列”;
1、当列数远大于行数时,“先行后列”的遍历时间最小。但在本次测试中发现是与调度遍历方式的顺序无关。
2、当行数远大于列数时,“先行后列”的遍历时间最小。调度顺序二明显使整体的遍历时间变小,但是增加了“先行后列”的遍历时间,减小了“先列后行”的遍历时间。
3、当行列数相等时,“先行后列”的遍历时间最小。调度顺序基本无影响。
4、当行列数都比较小时,遍历顺序基本无影响。
具体的解释可能与cache命中率有关,这里没有进行进一步的分析==
相关文章推荐
- 国外备份软件公司Acronis将采用区…
- 美商品期货交易委员会:区块链可应…
- 日本政府有望将比特币纳入法定货币
- 别指望比特币能取代美元 也别…
- Blockstack发布基于区块链的高安全…
- iOS上架总结
- 比特币会对中国的经济安全造成威胁…
- 澳洲证券投资委员会主席认为区块链…
- SWIFT:必须承认区块链在金融行业…
- 传统支付服务商开始推出基于区块链…
- DAH CEO:华尔街金融公司比区…
- 探索发现之Okhttp
- IT巨头Intel宣布在游戏中尝试全新…
- 欧洲议会发布数字货币监管草案并呼…
- Safe Cash Payment宣布…
- 费城安装第二台比特币ATM机
- Blockstream:区块链技术能给监管…
- 21 Inc比特币电脑现在被运至3…
- 为什么美共和党总统候选人和比特币…
- leetcode 310. Minimum Height Trees