与多行循环相比,单行循环是否节省了python代码的运行时间?
我想知道如何减少程序的运行时间。使用单线循环比多线循环更有效吗与多行循环相比,单行循环是否节省了python代码的运行时间?,python,performance,loops,Python,Performance,Loops,我想知道如何减少程序的运行时间。使用单线循环比多线循环更有效吗 #is this more efficient total_data = [[arr1[j][i] for j in range(3)]+ arr2[i][0] for i in range(10000)] #instead of total_data = [] for i in range(10000): arr3 = [] a2 = arr2[i][0] for j in range(3):
#is this more efficient
total_data = [[arr1[j][i] for j in range(3)]+ arr2[i][0] for i in range(10000)]
#instead of
total_data = []
for i in range(10000):
arr3 = []
a2 = arr2[i][0]
for j in range(3):
arr3.append(arr1[j][i])
total_data.append(arr3+a2)
另外,在调用函数时,使用map是否比for循环节省更多时间
#this
f1 = map(func1, var1, var2)
arr = map(func2, f2, var3, var4)
#instead of this
arr = []
for i in range(1000):
f1 = func1(var1(i), var2(i))
f2 = func2(f1(i))
arr.append(f2, var3, var4)
我的数据集很大,每个函数的运行时间也相当长,因此我希望尽可能减少时间。我想从根本上知道,在python中为同一个循环增加行数是否会增加时间。更多的代码行是否意味着更少的性能这一问题是有缺陷的,因为无论是
还是更少的行数≠ 演出≠ 更多行
。性能将取决于Python代码如何解析为执行它的底层C函数调用,这主要是解析器/解释器的实现细节,没有与行数的一对一等价
也就是说,在选择循环vs列表理解vs映射时,需要考虑以下几点
- 当代码的目的是创建一个列表时,列表理解通常比循环快。AFAIK这与对append方法的第二次do调用有关,还因为增量列表构造可能会导致列表调整大小,从而导致一些内存重新分配开销
- 无论调用python函数的位置如何,调用python函数都是一个缓慢的操作。引用如下:
函数调用需要操纵堆栈,将本地帧推到堆栈上,创建一个新帧,然后在函数返回时再次清除所有帧。
其中一个例外是用C编写的函数,例如模块中的函数,它们比本机Python对应函数稍快
也就是说,我已经使用类似的代码进行了一些评测,测试表明循环是最慢的选项。有趣的是,测试还显示map比列表理解略快(与链接答案相比)。代码和结果如下:
ls = list(range(1000000))
def f(x):
return x+1
def list_comprehension(ls):
return [f(x) for x in ls]
def for_loop(ls):
arr = []
for x in ls:
arr.append(f(x))
return arr
def map_(ls):
return list(map(f, ls))
if __name__ == "__main__":
import cProfile
for fn in [list_comprehension, for_loop, map_]:
print('=' * 25)
print("Profiling:", fn.__name__)
print('=' * 25)
pr = cProfile.Profile()
for i in range(1000):
pr.runcall(fn, ls)
pr.create_stats()
pr.print_stats()
# Output
=========================
Profiling: list_comprehension
=========================
1000003000 function calls in 235.641 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1000000000 104.000 0.000 104.000 0.000 aa.py:5(f)
1000 0.008 0.000 235.640 0.236 aa.py:8(list_comprehension)
1000 131.632 0.132 235.632 0.236 aa.py:9(<listcomp>)
1000 0.001 0.000 0.001 0.000 {method 'disable' of '_lsprof.Profiler' objects}
=========================
Profiling: for_loop
=========================
2000002000 function calls in 410.884 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1000 242.083 0.242 410.883 0.411 aa.py:11(for_loop)
1000000000 107.727 0.000 107.727 0.000 aa.py:5(f)
1000000000 61.073 0.000 61.073 0.000 {method 'append' of 'list' objects}
1000 0.001 0.000 0.001 0.000 {method 'disable' of '_lsprof.Profiler' objects}
=========================
Profiling: map_
=========================
1000002000 function calls in 205.035 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1000 102.451 0.102 205.034 0.205 aa.py:17(map_)
1000000000 102.583 0.000 102.583 0.000 aa.py:5(f)
1000 0.001 0.000 0.001 0.000 {method 'disable' of '_lsprof.Profiler' objects}
ls=列表(范围(1000000))
def f(x):
返回x+1
def列表(ls):
返回[f(x)表示ls中的x]
环路(ls)的def:
arr=[]
对于ls中的x:
arr.append(f(x))
返回arr
def映射(ls):
返回列表(地图(f、ls))
如果名称=“\uuuuu main\uuuuuuuu”:
导入cProfile
对于[列表\u理解,对于\u循环,映射\u]中的fn:
打印('='*25)
打印(“分析:”,fn.\u名称\u)
打印('='*25)
pr=cProfile.Profile()
对于范围(1000)内的i:
pr.runcall(fn,ls)
pr.create_stats()
公共印刷统计数据()
#输出
=========================
评测:列表
=========================
在235.641秒内调用100003000个函数
订购人:标准名称
ncalls tottime percall cumtime percall文件名:lineno(函数)
1000000000 104.000 0.000 104.000 0.000 aa.py:5(f)
1000 0.008 0.000 235.640 0.236 aa.py:8(列表)
1000 131.632 0.132 235.632 0.236 aa.py:9()
1000 0.001 0.000 0.001 0.000{方法'disable'的'lsprof.Profiler'对象}
=========================
评测:for_循环
=========================
在410.884秒内调用200002000个函数
订购人:标准名称
ncalls tottime percall cumtime percall文件名:lineno(函数)
1000 242.083 0.242 410.883 0.411 aa.py:11(用于_回路)
100000000 107.727 0.000 107.727 0.000 aa.py:5(f)
1000000000 61.073 0.000 61.073 0.000{“列表”对象的“附加”方法}
1000 0.001 0.000 0.001 0.000{方法'disable'的'lsprof.Profiler'对象}
=========================
剖析:地图_
=========================
在205.035秒内调用1000002000个函数
订购人:标准名称
ncalls tottime percall cumtime percall文件名:lineno(函数)
1000 102.451 0.102 205.034 0.205 aa.py:17(地图)
1000000000 102.583 0.000 102.583 0.000 aa.py:5(f)
1000 0.001 0.000 0.001 0.000{方法'disable'的'lsprof.Profiler'对象}
无论如何,在这种情况下,最好写下所有不同的版本,自己进行分析,而不是依赖于一般的假设。行数与代码的执行完全无关。py文件将被读取、解析和编译一次。在其上,将执行编译后的代码
换句话说,如果您创建一个包含10GB空白的文件,是的,这将影响解析时间,但即使这样,执行也不会受到影响
两种变体之间的区别在于,一种变体使用列表理解创建列表,而另一种变体创建一个空列表,然后填充它。我的直觉是,列表理解理论上更容易优化,但如果你真的关心细微的差异,你应该对其进行分析
另一方面,执行时间的微小差异很少能证明代码看起来更糟糕,因此默认情况下,您应该始终选择更优雅的解决方案。一行程序可能比更长的代码快,但这不是一般规则。有些python函数,如any(),all()允许非常紧凑的代码被优化以非常快地执行,并且可能比(例如)执行相同任务的两个嵌套循环更快。编译器/解释器并不真正关心需要处理多少文本(除非您的代码由数千行代码组成)。一个内衬是首选的,因为它节省了空间,使代码更加可读。在我看来,10000是一个小循环,不需要考虑单行或多行的效率。如果花费太多时间,可能芹菜就是解决办法。