循环结构的加速

时间:2013-11-22 17:28:59

标签: python performance list python-2.7 python-3.x

在以不同方式构建列表时,我注意到一些有趣的行为。 .append比列表推导需要更长的时间,而列表推导需要的时间超过map,如下面的实验所示:

def square(x): return x**2

def appendtime(times=10**6):
  answer = []
  start = time.clock()
  for i in range(times):
    answer.append(square(i))
  end = time.clock()
  return end-start

def comptime(times=10**6):
  start = time.clock()
  answer = [square(i) for i in range(times)]
  end = time.clock()
  return end-start

def maptime(times=10**6):
  start = time.clock()
  answer = map(square, range(times))
  end = time.clock()
  return end-start

for func in [appendtime, comptime, maptime]:
  print("%s: %s" %(func.__name__, func()))

Python 2.7:

appendtime: 0.42632
comptime: 0.312877
maptime: 0.232474

Python 3.3.3:

appendtime: 0.614167
comptime: 0.5506650000000001
maptime: 0.57115

现在,我非常清楚python 2.7中的range构建了一个列表,所以我知道为什么python 2.7和3.3中相应函数的时间之间存在差异。我更关心的是append,列表理解和map之间的相对时差。

首先,我认为这可能是因为map和列表推导可以让译员知道结果列表的最终大小,这将允许解释器在引擎盖下malloc一个足够大的C数组存储列表。按照这种逻辑,列表推导和map应该花费相同的时间 但是,时序数据显示,在python 2.7中,listcomps的速度比append快〜1.36倍,而map的速度比listcomps快〜1.34倍。
更奇怪的是,在python 3.3中,listcomps的速度是append的1.12倍,而map实际上比listcomps慢。

显然,map和listcomps不会“遵循相同的规则”;很明显,地图利用了listcomps没有的东西 任何人都可以了解这些时间价值差异背后的原因吗?

1 个答案:

答案 0 :(得分:1)

首先,在python3.x中,map返回iterable,而不是列表,这样就解释了50kx的加速比。为了使它成为合理的时机,在python3.x中你需要list(map(...))

其次,.append会慢一些,因为每次循环时,解释器需要查找列表,然后需要在列表中查找append函数。使用list-comp或map不需要进行额外的.append查找。

最后,通过list-comprehension,我相信在循环的每个回合都需要查找函数square。使用地图时,只有在调用地图时才会查找,这就是为什么如果你在列表理解中调用函数,map通常会更快。请注意,列表理解通常会使用map函数击败lambda