import itertools, time, math, random
class Point:
def __init__(self,x,y):
self.x, self.y = x, y
point_set = (Point(0, 0), Point(0, 1), Point(0, 2), Point(0, 3))
n_points = 100
pick_val = lambda : 10 * random.random() - 5
large_set = [Point(pick_val(), pick_val()) for _ in range(n_points)]
# the distance function
f_dist = lambda x0, x1, y0, y1: math.sqrt((x0 - x1) ** 2 + (y0 - y1) ** 2)
# go through each point, get its distance from all remaining points
f_pos = lambda p1, p2: (p1.x, p2.x, p1.y, p2.y)
extract_dists = lambda x: itertools.starmap(f_dist,
itertools.starmap(f_pos,
itertools.combinations(x, 2)))
print('Distances:', list(extract_dists(point_set)))
t0_f = time.time()
list(extract_dists(large_set))
dt_f = time.time() - t0_f
功能性版本比程序性版本快吗?
def extract_dists_procedural(pts):
n_pts = len(pts)
l = []
for k_p1 in range(n_pts - 1):
for k_p2 in range(k_p1, n_pts):
l.append((pts[k_p1].x - pts[k_p2].x) ** 2 +
(pts[k_p1].y - pts[k_p2].y) ** 2)
return l
t0_p = time.time()
list(extract_dists_procedural(large_set))
# using list() on the assumption that
# it eats up as much time as in the functional version
dt_p = time.time() - t0_p
f_vs_p = dt_p / dt_f
if f_vs_p >= 1.0:
print('Time benefit of functional progamming:', f_vs_p,
'times as fast for', n_points, 'points')
else:
print('Time penalty of functional programming:', 1 / f_vs_p,
'times as slow for', n_points, 'points')
8条答案
按热度按时间vh0rcniy1#
下面是一些基于经验的粗略指导和有根据的猜测,您应该
timeit
或剖析您的具体用例以获得确切的数字,这些数字可能偶尔与下面的数字不一致。列表解析通常比完全等价的
for
循环(实际构建列表)快一点点,很可能是因为它不必在每次迭代时查找列表及其append
方法。使用列表解析代替一个循环,它 * 不 * 构建列表,毫无意义地积累一个无意义值的列表,然后丢弃这个列表,通常会 * 慢 *,因为创建和扩展列表的开销很大。列表解析并不是魔术,它本质上比一个好的旧循环快。
对于功能列表处理函数:虽然这些都是用C编写的,并且可能比用Python编写的等效函数性能更好,但是它们 * 不 * 一定是最快的选择。如果函数也是用C编写的,那么速度会有所提高。但是大多数情况下使用
lambda
(或其他Python函数),重复设置Python堆栈帧等的开销会消耗掉所有的节省。而没有函数调用(例如,列表解析而不是map
或filter
)通常稍快。假设在我开发的一个游戏中,我需要使用for循环来绘制复杂而巨大的Map,这个问题肯定是相关的,因为如果列表理解确实更快,那么为了避免延迟,它将是一个更好的选择(尽管代码在视觉上很复杂)。
很有可能,如果用良好的非"优化" Python编写这样的代码还不够快,那么再多Python级别的微优化也不会使它足够快,您应该开始考虑降到C。虽然广泛的微优化通常可以显著提高Python代码的速度,但仍有很低的此外,即使在你达到这个上限之前,咬紧牙关写一些C语言也会变得更加经济高效(15%的加速比同样的努力300%的加速)。
whlutmcx2#
如果您查看www.example.com上的信息python.org,可以看到以下摘要:
但是您确实应该详细阅读上面的文章,以了解性能差异的原因。
我还强烈建议您使用timeit来计算代码的时间。在一天结束时,可能会出现这样的情况,例如,当满足某个条件时,您可能需要中断
for
循环。这可能比通过调用map
来查找结果更快。0g0grzrc3#
您特别询问了
map()
、filter()
和reduce()
,但我认为您想了解函数式编程的一般知识,我自己在计算一组点中所有点之间的距离的问题上测试了这个问题,函数式程序设计(使用内置itertools
模块中的starmap
函数)比for循环稍慢(实际上是for循环的1.25倍)。功能性版本比程序性版本快吗?
bwitn5fc4#
我修改了@Alisa的代码,并使用
cProfile
来说明为什么列表理解更快:以下是结果:
恕我直言:
reduce
和map
通常非常慢,不仅如此,与sum
处理列表相比,在map
返回的迭代器上使用sum
也很慢for_loop
使用append,这在某种程度上当然比较慢map
相比,list-comprehensive不仅构建列表花费的时间最少,而且使sum
的速度更快8zzbczxx5#
我写了一个简单的脚本来测试速度,这是我发现的。实际上for循环在我的例子中是最快的。这真的让我很惊讶,看看bellow(正在计算平方和)。
xsuvu9jc6#
我修改了@alpii的一些代码,发现列表解析比for循环快一些,这可能是
int()
造成的,列表解析和for循环之间不公平。fkaflof67#
对Alphii answer做一点改动,实际上for循环是第二好的,比
map
慢6倍左右主要的变化是消除了缓慢的
sum
调用,以及在最后一种情况下可能不必要的int()
。实际上,将for循环和map放在同一个术语中使其变得非常真实。请记住,lambda是函数概念,理论上不应该有副作用,但是,它们 * 可能 * 会有副作用,比如添加到a
。本例中的结果使用Python 3.6.1、Ubuntu 14.04、英特尔(R)酷睿(TM)i7-4770 CPU@3.40GHzbd1hkmkf8#
我正在寻找一些关于“for”循环和“list comprehension”的性能信息,偶然发现了这个主题。Python 3.11发布(2022年10月)已经有几个月了,Python 3.11的主要特性之一就是速度改进。https://www.python.org/downloads/release/python-3110/
Faster CPython项目已经产生了一些令人兴奋的结果。Python 3.11比Python 3.10快了10-60%。平均而言,我们测量了标准基准测试套件的1.22倍加速。参见Faster CPython了解详细信息。
我运行了最初由Alphi发布,然后由jjmerelo“扭曲”的相同代码。Python3.10和Python3.11的结果如下:
我还没有计算出确切的百分比改进,但很明显,性能增益-至少在这个特定的例子-似乎是令人印象深刻的(3至4倍的速度),除了'Map',它有微不足道的性能改进。
注:我在Windows 11下使用WSL运行的Kali Linux虚拟机上运行了这段代码。我不确定如果在Linux示例上原生运行(裸机),这段代码是否会执行得更好。
我的Kali Linux VM规格如下: