【问题标题】:Higher Order Functions vs loops - running time & memory efficiency?高阶函数与循环 - 运行时间和内存效率?
【发布时间】:2012-01-28 01:27:18
【问题描述】:

使用高阶函数和 Lambda 会使运行时间和内存效率提高还是降低? 例如,将列表中的所有数字相乘:

nums = [1,2,3,4,5]
prod = 1
for n in nums:
    prod*=n

prod2 = reduce(lambda x,y:x*y , nums)

除了更少的代码行/使用功能方法之外,HOF 版本是否比循环版本有任何优势?

编辑:

我无法将此添加为答案,因为我没有所需的声誉。 我按照@DSM 的建议使用 timeit 来分析循环和 HOF 方法

def test1():         
    s= """
    nums = [a for a in range(1,1001)] 
    prod = 1 
    for n in nums:
        prod*=n
    """            
    t = timeit.Timer(stmt=s)
    return t.repeat(repeat=10,number=100)    

def test2():
    s="""
    nums = [a for a in range(1,1001)]     
    prod2 = reduce(lambda x,y:x*y , nums)
    """
    t = timeit.Timer(stmt=s)
    return t.repeat(repeat=10,number=100) 

这是我的结果:

Loop:
[0.08340786340144211, 0.07211491653462579, 0.07162720686361926, 0.06593182661083438, 0.06399049758613146, 0.06605228229559557, 0.06419744588664211, 0.0671893658461038, 0.06477527090075941, 0.06418023793167627]
test1 average: 0.0644778902685
HOF:
[0.0759414223099324, 0.07616920129277016, 0.07570730355421262, 0.07604965128984942, 0.07547092059389193, 0.07544737286604364, 0.075532959799953, 0.0755039779810629, 0.07567424616704144, 0.07542563650187661]
test2 average: 0.0754917512762

平均而言,循环方法似乎比使用 HOF 更快。

【问题讨论】:

  • 你熟悉timeit模块吗?您可以自己测试性能。
  • 不,我不熟悉。我会用谷歌搜索timeit。我猜这是一个分析工具。但我仍然想从理论角度了解 HOF 的优势。
  • @RBK 问题在于理论视角无法回答您的问题(运行时间和内存效率)。
  • 查看Alex Martelli's answerMaking a flat list out of list of lists in Python 以获得一个很好的比较方法。
  • @DSM,我已经尝试使用 timeit 进行分析。我无法回答我自己的问题,因为我距离被允许回答我自己的问题还差 1 个声望点。我将尽快发布我的发现作为答案。

标签: python higher-order-functions


【解决方案1】:

高阶函数可以非常快。

例如,map(ord, somebigstring) 比等效的列表理解 [ord(c) for c in somebigstring]很多。前者获胜有三个原因:

  • map() 将结果字符串的大小预先设置为 somebigstring 的长度。相反,随着列表的增长,列表理解必须多次调用 realloc()

  • map() 只需对 ord 进行一次查找,首先检查全局变量,然后在内置函数中检查并找到它。列表推导必须在每次迭代中重复这项工作。

  • map 的内部循环以 C 速度运行。列表推导的循环体是一系列纯 Python 步骤,每个步骤都需要由 eval 循环分派或处理。

以下是确认预测的一些时间:

>>> from timeit import Timer
>>> print min(Timer('map(ord, s)', 's="x"*10000').repeat(7, 1000))
0.808364152908
>>> print min(Timer('[ord(c) for c in s]', 's="x"*10000').repeat(7, 1000))
1.2946639061

【讨论】:

  • 哦,我看到 map() 做很多事情比其他方式更有效。我想速度将取决于我们要完成的工作。 Making a flat list out of list of lists in Python 的讨论似乎表明 HOF 并不是最快的。
  • 使用 HOF 是该讨论的附带问题。那里的时间由其他因素决定,例如函数调用开销。
  • 是的,map 似乎更快了。我尝试了您的分析代码并得到了相同的结果。我将做更多的分析来说服自己:)
【解决方案2】:

根据我的经验,循环可以做得非常快,只要它们没有嵌套太深,并且具有复杂的高等数学运算,对于简单的运算和单层循环,它可以像任何其他方式一样快,也许更快,只要只使用整数作为循环或循环的索引,它实际上也取决于你在做什么

也很可能高阶函数会产生同样多的循环 作为循环程序版本,甚至可能会慢一点,您必须对它们进行计时...只是为了确定。

【讨论】:

    猜你喜欢
    • 2017-04-21
    • 1970-01-01
    • 1970-01-01
    • 2015-10-08
    • 2021-08-21
    • 2021-03-14
    • 1970-01-01
    • 1970-01-01
    • 2016-01-18
    相关资源
    最近更新 更多