作者:StarryLand

来源:https://www.starky.ltd/2021/11/23/the-fastest-way-to-loop-in-python

众所周知,Python 不是一种执行效率较高的语言。此外在任何语言中,循环都是一种非常消耗时间的操作。假如任意一种简单的单步操作耗费的时间为 1 个单位,将此操作重复执行上万次,最终耗费的时间也将增长上万倍。

whilefor 是 Python 中常用的两种实现循环的关键字,它们的运行效率实际上是有差距的。比如下面的测试代码:

import timeitdef while_loop(n=100_000_000):i = 0s = 0while i < n:s += ii += 1return sdef for_loop(n=100_000_000):s = 0for i in range(n):s += ireturn sdef main():print('while loop\t\t', timeit.timeit(while_loop, number=1))print('for loop\t\t', timeit.timeit(for_loop, number=1))if __name__ == '__main__':main()
# => while loop               4.718853999860585
# => for loop                 3.211570399813354

这是一个简单的求和操作,计算从 1 到 n 之间所有自然数的总和。可以看到 for 循环相比 while 要快 1.5 秒。

其中的差距主要在于两者的机制不同。

在每次循环中,while 实际上比 for 多执行了两步操作:边界检查和变量 i 的自增。即每进行一次循环,while 都会做一次边界检查 (while i < n)和自增计算(i +=1)。这两步操作都是显式的纯 Python 代码。

for 循环不需要执行边界检查和自增操作,没有增加显式的 Python 代码(纯 Python 代码效率低于底层的 C 代码)。当循环的次数足够多,就出现了明显的效率差距。

可以再增加两个函数,在 for 循环中加上不必要的边界检查和自增计算:

import timeitdef while_loop(n=100_000_000):i = 0s = 0while i < n:s += ii += 1return sdef for_loop(n=100_000_000):s = 0for i in range(n):s += ireturn sdef for_loop_with_inc(n=100_000_000):s = 0for i in range(n):s += ii += 1return sdef for_loop_with_test(n=100_000_000):s = 0for i in range(n):if i < n:passs += ireturn sdef main():print('while loop\t\t', timeit.timeit(while_loop, number=1))print('for loop\t\t', timeit.timeit(for_loop, number=1))print('for loop with increment\t\t',timeit.timeit(for_loop_with_inc, number=1))print('for loop with test\t\t', timeit.timeit(for_loop_with_test, number=1))if __name__ == '__main__':main()
# => while loop               4.718853999860585
# => for loop                 3.211570399813354
# => for loop with increment          4.602369500091299
# => for loop with test               4.18337869993411

可以看出,增加的边界检查和自增操作确实大大影响了 for 循环的执行效率。

前面提到过,Python 底层的解释器和内置函数是用 C 语言实现的。而 C 语言的执行效率远大于 Python。

对于上面的求等差数列之和的操作,借助于 Python 内置的 sum 函数,可以获得远大于 forwhile 循环的执行效率。

import timeitdef while_loop(n=100_000_000):i = 0s = 0while i < n:s += ii += 1return sdef for_loop(n=100_000_000):s = 0for i in range(n):s += ireturn sdef sum_range(n=100_000_000):return sum(range(n))def main():print('while loop\t\t', timeit.timeit(while_loop, number=1))print('for loop\t\t', timeit.timeit(for_loop, number=1))print('sum range\t\t', timeit.timeit(sum_range, number=1))if __name__ == '__main__':main()
# => while loop               4.718853999860585
# => for loop                 3.211570399813354
# => sum range                0.8658821999561042

可以看到,使用内置函数 sum 替代循环之后,代码的执行效率实现了成倍的增长。

内置函数 sum 的累加操作实际上也是一种循环,但它由 C 语言实现,而 for 循环中的求和操作是由纯 Python 代码 s += i 实现的。C > Python。

再拓展一下思维。小时候都听说过童年高斯巧妙地计算 1 到 100 之和的故事。1…100 之和等于 (1 + 100) * 50。这个计算方法同样可以应用到上面的求和操作中。

import timeitdef while_loop(n=100_000_000):i = 0s = 0while i < n:s += ii += 1return sdef for_loop(n=100_000_000):s = 0for i in range(n):s += ireturn sdef sum_range(n=100_000_000):return sum(range(n))def math_sum(n=100_000_000):return (n * (n - 1)) // 2def main():print('while loop\t\t', timeit.timeit(while_loop, number=1))print('for loop\t\t', timeit.timeit(for_loop, number=1))print('sum range\t\t', timeit.timeit(sum_range, number=1))print('math sum\t\t', timeit.timeit(math_sum, number=1))if __name__ == '__main__':main()
# => while loop               4.718853999860585
# => for loop                 3.211570399813354
# => sum range                0.8658821999561042
# => math sum                 2.400018274784088e-06

最终 math sum 的执行时间约为 2.4e-6,缩短了上百万倍。这里的思路就是,既然循环的效率低,一段代码要重复执行上亿次。

索性直接不要循环,通过数学公式,把上亿次的循环操作变成只有一步操作。效率自然得到了空前的加强。

最后的结论(有点谜语人):

实现循环的最快方式—— —— ——就是不用循环

对于 Python 而言,则尽可能地使用内置函数,将循环中的纯 Python 代码降到最低。

参考资料

The Fastest Way to Loop in Python - mCoding  (https://youtu.be/Qgevy75co8c)

各位伙伴们好,詹帅本帅搭建了一个个人博客和小程序,汇集各种干货和资源,也方便大家阅读,感兴趣的小伙伴请移步小程序体验一下哦!(欢迎提建议)

推荐阅读

牛逼!Python常用数据类型的基本操作(长文系列第①篇)

牛逼!Python的判断、循环和各种表达式(长文系列第②篇)

牛逼!Python函数和文件操作(长文系列第③篇)

牛逼!Python错误、异常和模块(长文系列第④篇)

Python 实现循环的最快方式(for、while 等速度对比)相关推荐

  1. python For 循环 三种遍历方式

    array = ["a","b","c"]for item in array:print(item)for index in range(l ...

  2. python中循环语句的用法,python几种循环方式

    python中while循环的用法是什么? python while循环语句:while 判断条件(condition):执行语句(statements)--执行语句可以是单个语句或语句块. 判断条件 ...

  3. python文件中用逗号分隔_在python中读取逗号分隔文件(包括日期)的最快方式

    我有数据存储在逗号分隔的txt文件中.其中一列表示日期时间. 我需要将每个列加载到单独的numpy数组中(并将日期解码为python datetime对象). 最快的方法是什么(就运行时间而言)? 注 ...

  4. 独家 | 数据科学家的必备读物:从零开始用 Python 构建循环神经网络(附代码)...

    作者:Faizan Shaikh 翻译:李文婧 校对:张一豪 本文约4300字,建议阅读10+分钟. 本文带你快速浏览典型NN模型核心部分,并教你构建RNN解决相关问题. 引言 人类不会每听到一个句子 ...

  5. Python MySQLdb 循环插入execute与批量插入executemany性能分析(list批量写法亲测成功)

    用Python连接MySQL数据库时,会用到MySQLdb库,这里下载↓↓↓ https://pypi.python.org/pypi/MySQL-python/ 这个库提供了对数据库的普遍操作,增删 ...

  6. python读什么文件最快的软件_这些方法,能够让你的 Python 程序快如闪电

    原标题:这些方法,能够让你的 Python 程序快如闪电 来源:机器之心 讨厌 Python 的人总是会说,他们不想用 Python 的一个重要原因是 Python 很慢.而事实上,无论使用什么编程语 ...

  7. 用 PyPy 让你的 Python 代码运行得更快!

    Python是开发人员中最常用的编程语言之一,但它有一定的局限性.例如,对于某些应用程序而言,它的运行速度可能比其它语言低100倍.这就是为什么当Python的运行速度成为用户瓶颈后,许多公司会用另一 ...

  8. python处理csv数据-分分快3大小

    .NET Core教程 .NET Core是Microsoft最新的通用开发平台.它可以在不同的平台上工作,并且已经被重新设计,使.NET变得快速,灵活和现代. A/B测试教程 A/B测试是比较两个或 ...

  9. Python 文件读取的4种方式

    python读文件的4种方式 1.直接打开就读 with open('filepath','r') as f:for line in f:print(line)print('一行数据') 虽然f是一个 ...

最新文章

  1. mongodb气势如虹
  2. uva 11732 - strcmp() Anyone? 不错的Trie题
  3. git教程——简单总结
  4. 【转】android之在activity中控制另一个activity的UI更新_如何在activity之间传递handler...
  5. 移动硬盘函数不正确要如何寻回资料
  6. cf两边黑屏怎么解决win10_关闭自动睡眠仍然睡眠?Win10过几分钟就会自动睡眠黑屏解决方法...
  7. js中数字直接点方法会报错,如1.toString()
  8. line java_java – Line Rasterization / 4-bresenham
  9. get buffer from CMSampleBufferRef
  10. Linux基础-1.Linux命令及获取帮助
  11. 使用ecstore-sdk开发包制作易开店和启明星模板
  12. leetcode每日一题2021.7.14【1818. 绝对差值和】
  13. 二项式定理学习笔记(详解)
  14. Verilog中按键消抖检测的实现
  15. PS4 不支持USB存储设备的文件系统 如何解决?
  16. 如画的水乡,如画的同里58
  17. linux用飞信发短信
  18. 求无向图的连通分量或有向图的强连通分量—tarjan()ccf高速公路
  19. http状态码大全,从100-505状态码详情
  20. POE供电怎么用?常见PoE供电4种工程应用方法

热门文章

  1. rabbit以及php amqp扩展使用
  2. php 利用debug_backtrace方法跟踪代码调用
  3. redis和kafka比较
  4. linux php7 安装redis扩展(php7可以使用自测)
  5. 统计Apache或nginx日志里访问次数最多的前十个IP
  6. MySQL中merge表存储引擎用法
  7. java cookie 加密_java cookie encodeBase64加密
  8. java 概率 算法_使用概率算法优化快速排序(JAVA)
  9. 您拒绝了位置共享服务器,共享服务器拒绝访问
  10. linux 如何创建内核进程,Linux内核的进程创建和执行.pdf