多重 for 循环,应该如何提高效率?

道阻且长,行则将至。埋头苦干,不鸣则已,一鸣惊人!加油,骚年!

前言

  我在《华为 C 语言编程规范》中看到了这个:当使用多重循环时,应该将最忙的循环放在最内层。如下图:

image-20200827225125779

  由上述很简单的伪代码可以看到,推荐使用的方式是:外小内大的方式。也就是内层循环是最忙的。

  然后我又在另外一份编程规范手册中,看到了类似的要求,如下图:

image-20200827225924962

  看到了这个小技巧之后,我迫不及待的分享给我的小伙伴,后来闲下来的时候,就想自己做个测试,验证一下是否真的是这样。

Ubuntu 测试

  使用 Ubuntu 14.04 的系统进行测试,基本信息如下:

  • 系统版本:Ubuntu14.04
  • gcc 版本:4.8.2

  我使用了两份不同的代码文件进行测试,第一份是 外大内小 的代码,如下:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>

using namespace std;

int main()
{
	struct timeval tv;
	unsigned long ulStartTime, ulEndTime;

	gettimeofday(&tv, NULL);                               // 获取当前时间
	ulStartTime = tv.tv_sec * 1000000 + tv.tv_usec;        // 计算当前起始时间
	cout << "start time = " << ulStartTime << endl;        // 打印显示
	for(unsigned int i = 0; i < 1000000; i++)              // 测试代码
	{
		for(int j = 0; j < 100; j++)
		{
			
		}
	}
	gettimeofday(&tv, NULL);
	ulEndTime = tv.tv_sec * 1000000 + tv.tv_usec;          // 计算结束时间
	cout << "end time = " << ulEndTime << endl;            // 打印结束时间
	cout << "Time = " << ulEndTime - ulStartTime << endl;  // 计算时间差值 微秒 us
}

  执行上述代码,运行结果如下,耗时:165280us

image-20200827232438226

  接着,我又准备了另外一份 外小内大 的代码,对比只是调换了 for 循环内外层的循环次数而已,如下:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>

using namespace std;

int main()
{
	struct timeval tv;
	unsigned long ulStartTime, ulEndTime;

	gettimeofday(&tv, NULL);
	ulStartTime = tv.tv_sec * 1000000 + tv.tv_usec;
	cout << "start time = " << ulStartTime << endl;
	for(int i = 0; i < 100; i++)
	{
		for(unsigned int j = 0; j < 1000000; j++)
		{

		}
	}
	gettimeofday(&tv, NULL);
	ulEndTime = tv.tv_sec * 1000000 + tv.tv_usec;
	cout << "end time = " << ulEndTime << endl;
	cout << "Time = " << ulEndTime - ulStartTime << endl;
}

  上述代码的执行结果如下,耗时:155960us

image-20200827232700030

  对比上述两份代码的运行结果,可以很明显的看到,外小内大效率更高一点!

  不过,你以为这就结束了吗?

树莓派测试

  手边刚好有一台树莓派,前段时间刚安装了最新的官方系统,就想着拿来做一下测试,基本信息如下:

  • 树莓派系统版本:buster

image-20200827233614235

image-20200827233640472

  • g++ 版本:8.3.0

image-20200827233726695

  测试代码与在 Ubuntu 上运行的代码保持一致,这里就不重复贴代码了,只看一下运行结果。

  下边这个是 外大内小 的,运行结果如下,耗时:1214569us

image-20200827234131317

  这个是 外小内大 的,运行结果如下,耗时:1345193us

image-20200827234253265

  完了,可以很明显的看到,外大内小 的运行效率要更高一点。

问题分析

  我也是有点蒙逼的,不知道为啥会出现截然相反的情况,对比两个系统版本,硬件设备来看,推测原因有如下几种可能:

  • 处理器架构不同

    • Ubuntu 是安装在 win10 台式机上的虚拟机中,所使用的硬件应该为台式机的硬件(处理器等);而台式机的硬件是英特尔的 X86 架构的处理器。
    • 树莓派使用的硬件平台,是一个 ARM 架构的芯片,具体可以参考图片:

  • gcc 版本不同,在刚开始操作的时候,也详细的列出了当前程序使用的环境

    • Ubuntu14.04 中 gcc 版本为:4.8.2
    • 树莓派中 gcc 版本为:8.3.0

  目前能想到的差异就这么多,其他的暂时还不知道,难道这个就是运行在 X86 平台和 ARM 平台的区别之一?更多的更深入的研究还有待后续学习研究才能知道。今天的讨论就到这里为止吧!

总结

  1. 在 X86 架构平台下,外小内大效率较高;
  2. 由于参考的规范手册,可能是用于服务器开发,而服务器仍然是 X86 架构的处理器居多,因此 for 循环的多重循环规则较适用;
  3. 需要考虑在嵌入式等 ARM 平台下,此规则是否同样适用,是否还有其他应用场景限制等?

如果文章内容有误,麻烦评论/私信多多指教,谢谢!如果觉得文章内容还不错,记得一键三连哦(点赞、收藏、留言),您的支持就是对我最大的鼓励,谢谢您嘞!

在Python编程中,循环是非常常见和重要的数据处理方式。然而,Python的解释性语言特性,对循环的执行效率会有一定的影响。因此,在处理大量数据和复杂计算时,循环效率的提升显得尤为重要。下面从以下几个方面介绍如何提高Python for循环效率。 1.列表推导式 列表推导式是Python中比较高效的列表生成方式,可以用快速生成列表。例如: ``` squares = [x**2 for x in range(10)] ``` 这个列表推导式相当于以下for循环: ``` squares = [] for x in range(10): squares.append(x**2) ``` 通过使用列表推导式,可以避免在循环中使用append()方法将元素一个一个添加到列表中的效率问题,从而提高for循环的效率。 2.使用range()函数代替enumerate()迭代器 在Python中,enumerate()迭代器可以同时获取索引和元素。然而,在对于大量数据的处理过程中,enumerate()迭代器效率较低。此时,可以使用Python自带的range函数来替代enumerate迭代器进行遍历,例如: ``` lst = ['a', 'b', 'c', 'd', 'e'] for i in range(len(lst)): print(i, lst[i]) ``` 3.尽量避免多重循环和嵌套 在Python中,多重循环(nested loops)和嵌套会增加时间复杂度,导致程序效率变低。因此,在编写代码时,应该尽量避免多重循环和嵌套的情况,并尝试使用其他算法解决问题。 4.使用map()和filter()函数 Python中的map()和filter()函数可以用来代替循环操作,从而实现高效的数据处理和计算。map()函数可以对序列中每个元素进行操作,filter()函数可以对序列中每个元素进行筛选。例如: ``` lst = [1, 2, 3, 4, 5] new_lst = list(map(lambda x: x**2, lst)) new_lst = list(filter(lambda x: x % 2 == 0, lst)) ``` 这里利用map()和filter()函数实现了对列表中每个元素的平方和偶数筛选,从而避免了显式的循环操作。 总之,Python的循环效率可以通过多种方式进行提高,例如列表推导式、range()函数代替enumerate()迭代器、避免多重循环和嵌套及使用map()和filter()函数等方法。在实际使用中,我们应该根据情况选择合适的方法来提高程序的效率,从而减少计算时间和提高程序的性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FightingBoom

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值