加速 Python for 循环(python加快循环速度)
off999 2024-10-23 12:50 43 浏览 0 评论
在接下来的内容中,我会给大家分享一些简便的方式,能够让 Python for 循环的速度实现 1.3 至 900 倍的提升。
Python 自身所具备的一个常用功能是 timeit 模块。在后续的几个部分中,我们会借助它来衡量循环当前的性能表现以及改进之后的性能状况。
对于每一种方法,我们都通过运行测试来设定基线,该测试涵盖了在 10 次测试运行中对被测函数执行 100K 次(循环),接着计算出每个循环的平均时间(以纳秒为单位,ns)。
几个简便方法
1、列表推导式
基线版本(低效方式)
计算数字的幂
未使用列表推导式
def test_01_v0(numbers):
output = []
for n in numbers:
output.append(n ** 2.5)
return output
改进版本
(使用列表推导式)
def test_01_v1(numbers):
output = [n ** 2.5 for n in numbers]
return output
测试结果如下:
测试结果汇总
基线:32.158 ns 每个循环
改进:16.040 ns 每个循环
% 改进:50.1 %
加速:2.00x
能够看到,运用列表推导式能够实现 2 倍速的提升。
2、在外部计算长度
倘若需要依据列表的长度进行迭代,那么就在 for 循环之外进行计算。
基线版本(低效方式)
(在 for 循环内部计算长度)
def test_02_v0(numbers):
output_list = []
for i in range(len(numbers)):
output_list.append(i * 2)
return output_list
改进版本
(在 for 循环外部计算长度)
def test_02_v1(numbers):
my_list_length = len(numbers)
output_list = []
for i in range(my_list_length):
output_list.append(i * 2)
return output_list
通过将列表长度的计算移出 for 循环,实现了 1.6 倍的加速,或许这个方法鲜为人知。
测试结果汇总
基线:112.135 ns 每个循环
改进:68.304 ns 每个循环
% 改进:39.1 %
加速:1.64x
3、使用 Set
在通过 for 循环进行比较的情形下使用 set。
使用 for 循环进行嵌套查找
def test_03_v0(list_1, list_2):
基线版本(低效方式)
(使用 for 循环进行嵌套查找)
common_items = []
for item in list_1:
if item in list_2:
common_items.append(item)
return common_items
def test_03_v1(list_1, list_2):
改进版本
(使用 set 替代嵌套查找)
s_1 = set(list_1)
s_2 = set(list_2)
output_list = []
common_items = s_1.intersection(s_2)
return common_items
在使用嵌套 for 循环进行比较的情况下,使用 set 能够实现 498 倍的加速。
测试结果汇总
基线:9047.078 ns 每个循环
改进: 18.161 ns 每个循环
% 改进:99.8 %
加速:498.17x
4、跳过不相关的迭代
避免冗余计算,也就是跳过不相关的迭代。
低效代码示例,用于在数字列表中查找第一个偶数平方
def function_do_something(numbers):
for n in numbers:
square = n * n
if square % 2 == 0:
return square
return None # 未找到偶数平方
改进后的代码,在查找结果时避免冗余计算
def function_do_something_v1(numbers):
even_numbers = [i for n in numbers if n%2==0]
for n in even_numbers:
square = n * n
return square
return None # 未找到偶数平方
这个方法需要在设计 for 循环的内容时进行代码规划,具体能够提升的幅度可能因实际情况而有所不同:
测试结果汇总
基线:16.912 ns 每个循环
改进:8.697 ns 每个循环
% 改进:48.6 %
加速:1.94x
5、代码合并
在某些情形下,直接把简单函数的代码融入到循环中,能够提高代码的紧凑性和执行速度。
低效代码示例
循环中多次调用 is_prime 函数
def is_prime(n):
if n <= 1:
return False
for i in range(2, int(n**0.5) + 1):
if n % i == 0:
return False
return True
def test_05_v0(n):
基线版本(低效方式)
(多次调用 is_prime 函数)
count = 0
for i in range(2, n + 1):
if is_prime(i):
count += 1
return count
def test_05_v1(n):
改进版本
(将 is_prime 函数的逻辑内联)
count = 0
for i in range(2, n + 1):
if i <= 1:
continue
for j in range(2, int(i**0.5) + 1):
if i % j == 0:
break
else:
count += 1
return count
这样也能够实现 1.3 倍的提升。
测试结果汇总
基线:1271.188 ns 每个循环
改进:939.603 ns 每个循环
% 改进:26.1 %
加速:1.35x
这是为何呢?
调用函数会产生开销,例如在堆栈上推入和弹出变量、进行函数查找以及参数传递。当一个简单的函数在循环中被反复调用时,函数调用的开销会增加并影响性能。所以将函数的代码直接嵌入到循环中能够消除这种开销,从而有可能显著提升速度。
??但在此需要注意,平衡代码的可读性和函数调用的频率是一个需要考虑的问题。
一些小技巧
6. 避免重复
思考避免重复计算,其中有些计算可能是多余的,并且会拖慢代码的速度。相反,在适用的情况下考虑预计算。
def test_07_v0(n):
低效代码示例
嵌套循环中的重复计算
result = 0
for i in range(n):
for j in range(n):
result += i * j
return result
def test_07_v1(n):
改进代码示例
利用预计算值来加速
pv = [[i * j for j in range(n)] for i in range(n)]
result = 0
for i in range(n):
result += sum(pv[i][:i+1])
return result
结果如下
测试结果汇总
基线:139.146 ns 每个循环
改进:92.325 ns 每个循环
% 改进:33.6 %
加速:1.51x
7、使用 Generators
生成器支持延迟求值,也就是说,只有当向它请求下一个值时,内部的表达式才会被计算,动态处理数据有助于减少内存使用并提升性能。尤其是在处理大型数据集时
def test_08_v0(n):
基线版本(低效方式)
(低效地计算第 n 个斐波那契数,使用列表)
if n <= 1:
return n
f_list = [0, 1]
for i in range(2, n + 1):
f_list.append(f_list[i - 1] + f_list[i - 2])
return f_list[n]
def test_08_v1(n):
改进版本
(高效地计算第 n 个斐波那契数,使用生成器)
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
能够看到提升非常显著:
测试结果汇总
基线:0.083 ns 每个循环
改进:0.004 ns 每个循环
% 改进:95.5 %
加速:22.06x
8、map()函数
使用 Python 内置的 map()函数。它允许在不使用显式 for 循环的情况下处理和转换可迭代对象中的所有项。
def some_function_X(x):
通常这会是一个包含应用逻辑的函数
(为了本次测试的目的,仅计算并返回平方)
return x**2
def test_09_v0(numbers):
基线版本(低效方式)
output = []
for i in numbers:
output.append(some_function_X(i))
return output
def test_09_v1(numbers):
改进版本
(使用 Python 内置的 map()函数)
output = map(some_function_X, numbers)
return output
使用 Python 内置的 map()函数替代显式的 for 循环,实现了 970 倍的加速。
测试结果汇总
基线:4.402 ns 每个循环
改进:0.005 ns 每个循环
% 改进:99.9 %
加速:970.69x
这是为什么呢?
map()函数是用 C 语言编写的,并且经过了高度优化,因此它内部隐含的循环比常规的 Python for 循环高效得多。所以速度得到了提升,或者也可以说 Python 本身还是太慢,哈。
9、使用 Memoization
记忆优化算法的理念是缓存(或“记忆”)昂贵函数调用的结果,并在出现相同输入时返回它们。它能够减少冗余计算,加快程序速度。
首先是低效的版本。
低效代码示例
def fibonacci(n):
if n == 0:
return 0
elif n == 1:
return 1
return fibonacci(n - 1) + fibonacci(n-2)
def test_10_v0(list_of_numbers):
output = []
for i in numbers:
output.append(fibonacci(i))
return output
然后我们使用 Python 内置的 functools 的 lru_cache 函数。
高效代码示例
使用 Python 的 functools 的 lru_cache 函数
import functools
@functools.lru_cache()
def fibonacci_v2(n):
if n == 0:
return 0
elif n == 1:
return 1
return fibonacci_v2(n - 1) + fibonacci_v2(n-2)
def _test_10_v1(numbers):
output = []
for i in numbers:
output.append(fibonacci_v2(i))
return output
结果如下:
测试结果汇总
基线:63.664 ns 每个循环
改进:1.104 ns 每个循环
% 改进:98.3 %
加速:57.69x
使用 Python 的内置 functools 的 lru_cache 函数并运用 Memoization 实现了 57 倍的加速。
lru_cache 函数是如何实现的?
“LRU”是“Least Recently Used”的缩写。lru_cache 是一个装饰器,能够应用于函数以启用 memoization。它会将最近函数调用的结果存储在缓存中,当再次出现相同的输入时,能够提供缓存的结果,从而节省计算时间。lru_cache 函数,在作为装饰器应用时,允许一个可选的 maxsize 参数,maxsize 参数决定了缓存的最大大小(即,它为多少个不同的输入值存储结果)。如果 maxsize 参数设置为 None,则禁用 LRU 特性,缓存可以不受限制地增长,这会消耗大量的内存。这是最简单的空间换时间的优化方法。
10、向量化
import numpy as np
def test_11_v0(n):
基线版本
(低效的求和方式)
output = 0
for i in range(0, n):
output = output + i
return output
def test_11_v1(n):
改进版本
(高效的求和方式)
output = np.sum(np.arange(n))
return output
向量化通常用于机器学习的数据处理库 numpy 和 pandas
测试结果汇总
基线:32.936 ns 每个循环
改进:1.171 ns 每个循环
% 改进:96.4 %
加速:28.13x
11、避免创建中间列表
使用 filterfalse 能够避免创建中间列表。它有助于减少内存使用。
def test_12_v0(numbers):
基线版本(低效方式)
filtered_data = []
for i in numbers:
filtered_data.extend(list(
filter(lambda x: x % 5 == 0,
range(1, i**2))))
return filtered_data
使用 Python 内置的 itertools 的 filterfalse 函数实现相同功能的改进版本。
from itertools import filterfalse
def test_12_v1(numbers):
改进版本
(使用 filterfalse)
filtered_data = []
for i in numbers:
filtered_data.extend(list(
filterfalse(lambda x: x % 5!= 0,
range(1, i**2))))
return filtered_data
这个方法依据具体的用例,执行速度可能没有显著提升,但通过避免创建中间列表能够降低内存使用。我们在此获得了 131 倍的提升
测试结果汇总
基线:333167.790 ns 每个循环
改进:2541.850 ns 每个循环
% 改进:99.2 %
加速:131.07x
12、高效连接字符串
任何使用 + 操作符进行的字符串连接操作都会很慢,并且会消耗更多内存。使用 join 替代。
def test_13_v0(l_strings):
基线版本(低效方式)
(使用 += 操作符进行连接)
output = ""
for a_str in l_strings:
output += a_str
return output
def test_13_v1(numbers):
改进版本
(使用 join)
output_list = []
for a_str in l_strings:
output_list.append(a_str)
return "".join(output_list)
该测试需要一种简便的方法来生成一个较大的字符串列表,所以编写了一个简单的辅助函数来生成运行测试所需的字符串列表。
from faker import Faker
def generate_fake_names(count : int=10000):
辅助函数,用于生成
一个较大的名字列表
fake = Faker()
output_list = []
for _ in range(count):
output_list.append(fake.name())...
相关推荐
- 安全教育登录入口平台(安全教育登录入口平台官网)
-
122交通安全教育怎么登录:122交通网的注册方法是首先登录网址http://www.122.cn/,接着打开网页后,点击右上角的“个人登录”;其次进入邮箱注册,然后进入到注册页面,输入相关信息即可完...
- 大鱼吃小鱼经典版(大鱼吃小鱼经典版(经典版)官方版)
-
大鱼吃小鱼小鱼吃虾是于谦跟郭麒麟的《我的棒儿呢?》郭德纲说于思洋郭麒麟作诗的相声,最后郭麒麟做了一首,师傅躺在师母身上大鱼吃小鱼小鱼吃虾虾吃水水落石出师傅压师娘师娘压床床压地地动山摇。...
-
- 哪个软件可以免费pdf转ppt(免费的pdf转ppt软件哪个好)
-
要想将ppt免费转换为pdf的话,我们建议大家可以下一个那个wps,如果你是会员的话,可以注册为会员,这样的话,在wps里面的话,就可以免费将ppt呢转换为pdfpdf之后呢,我们就可以直接使用,不需要去直接不需要去另外保存,为什么格式转...
-
2026-02-04 09:03 off999
- 电信宽带测速官网入口(电信宽带测速官网入口app)
-
这个网站看看http://www.swok.cn/pcindex.jsp1.登录中国电信网上营业厅,宽带光纤,贴心服务,宽带测速2.下载第三方软件,如360等。进行在线测速进行宽带测速时,尽...
- 植物大战僵尸95版手机下载(植物大战僵尸95 版下载)
-
1可以在应用商店或者游戏平台上下载植物大战僵尸95版手机游戏。2下载教程:打开应用商店或者游戏平台,搜索“植物大战僵尸95版”,找到游戏后点击下载按钮,等待下载完成即可安装并开始游戏。3注意:确...
- 免费下载ppt成品的网站(ppt成品免费下载的网站有哪些)
-
1、Chuangkit(chuangkit.com)直达地址:chuangkit.com2、Woodo幻灯片(woodo.cn)直达链接:woodo.cn3、OfficePlus(officeplu...
- 2025世界杯赛程表(2025世界杯在哪个国家)
-
2022年卡塔尔世界杯赛程公布,全部比赛在卡塔尔境内8座球场举行,2022年,决赛阶段球队全部确定。揭幕战于当地时间11月20日19时进行,由东道主卡塔尔对阵厄瓜多尔,决赛于当地时间12月18日...
- 下载搜狐视频电视剧(搜狐电视剧下载安装)
-
搜狐视频APP下载好的视频想要导出到手机相册里方法如下1、打开手机搜狐视频软件,进入搜狐视频后我们点击右上角的“查找”,找到自已喜欢的视频。2、在“浏览器页面搜索”窗口中,输入要下载的视频的名称,然后...
- 永久免费听歌网站(丫丫音乐网)
-
可以到《我爱音乐网》《好听音乐网》《一听音乐网》《YYMP3音乐网》还可以到《九天音乐网》永久免费听歌软件有酷狗音乐和天猫精灵,以前要跳舞经常要下载舞曲,我从QQ上找不到舞曲下载就从酷狗音乐上找,大多...
- 音乐格式转换mp3软件(音乐格式转换器免费版)
-
有两种方法:方法一在手机上操作:1、进入手机中的文件管理。2、在其中选择“音乐”,将显示出手机中的全部音乐。3、点击“全选”,选中所有音乐文件。4、点击屏幕右下方的省略号图标,在弹出菜单中选择“...
- 电子书txt下载(免费的最全的小说阅读器)
-
1.Z-library里面收录了近千万本电子书籍,需求量大。2.苦瓜书盘没有广告,不需要账号注册,使用起来非常简单,直接搜索预览下载即可。3.鸠摩搜书整体风格简洁清晰,书籍资源丰富。4.亚马逊图书书籍...
- 最好免费观看高清电影(播放免费的最好看的电影)
-
在目前的网上选择中,IMDb(互联网电影数据库)被认为是最全的电影网站之一。这个网站提供了各种类型的电影和电视节目的海量信息,包括剧情介绍、演员表、评价、评论等。其还提供了有关电影制作背后的详细信息,...
- 孤单枪手2简体中文版(孤单枪手2简体中文版官方下载)
-
要将《孤胆枪手2》游戏的征兵秘籍切换为中文,您可以按照以下步骤进行操作:首先,打开游戏设置选项,通常可以在游戏主菜单或游戏内部找到。然后,寻找语言选项或界面选项,点击进入。在语言选项中,选择中文作为游...
欢迎 你 发表评论:
- 一周热门
- 最近发表
- 标签列表
-
- python计时 (73)
- python安装路径 (56)
- python类型转换 (93)
- python进度条 (67)
- python吧 (67)
- python的for循环 (65)
- python格式化字符串 (61)
- python静态方法 (57)
- python列表切片 (59)
- python面向对象编程 (60)
- python 代码加密 (65)
- python串口编程 (77)
- python封装 (57)
- python写入txt (66)
- python读取文件夹下所有文件 (59)
- python操作mysql数据库 (66)
- python获取列表的长度 (64)
- python接口 (63)
- python调用函数 (57)
- python多态 (60)
- python匿名函数 (59)
- python打印九九乘法表 (65)
- python赋值 (62)
- python异常 (69)
- python元祖 (57)
