我当时正在研究Python生成器,并决定进行一些实验。

TOTAL = 100000000
def my_sequence():
    i = 0
    while i < TOTAL:
        yield i
        i += 1

def my_list():
    return range(TOTAL)

def my_xrange():
    return xrange(TOTAL)

在多次运行每种方法并取平均值之后,下面显示了内存使用情况(使用psutil获取进程RSS内存)和所花费的时间(使用time.time())。
sequence_of_values = my_sequence() # Memory usage: 6782976B  Time taken: 9.53674e-07 s

sequence_of_values2 = my_xrange() # Memory usage: 6774784B  Time taken: 2.14576e-06 s

list_of_values = my_list() # Memory usage: 3266207744B  Time taken: 1.80253s

我注意到,使用xrange生成生成器始终比使用yield来生成生成器慢(略)。为什么会这样?

最佳答案

我将以这个答案作为开头,说这种规模的时间可能很难精确测量(最好使用timeit),并且这些优化几乎不会对您实际程序的运行时产生任何影响。 。

好的,现在免责声明已完成...

您需要注意的第一件事是,您仅对生成器/xrange对象的构建进行计时-您而不是计时实际迭代值所需的时间。在某些情况下,创建生成器可能比创建xrange对象更快的原因有两个。

  • 对于生成器而言,您仅创建一个生成器-生成器中的任何代码实际上都不会运行。这大约相当于1个函数调用。
  • 对于xrange情况,您要调用该函数,然后必须查找全局名称xrange和全局TOTAL,然后需要调用该内建函数-因此,在这种情况下将执行更多的操作。

  • 至于内存-在这两种惰性方法中,使用的内存将由python运行时控制-而不是生成器对象的大小。脚本会显着影响内存使用的唯一情况是构造1亿个项目的列表的情况。

    还要注意,我实际上无法在系统上一致地确认您的结果...使用timeit,我实际上得到my_xrange的构造有时会快2倍(约30%)。

    将以下内容添加到脚本的底部:
    from timeit import timeit
    print timeit('my_xrange()', setup='from __main__ import my_xrange')
    print timeit('my_sequence()', setup='from __main__ import my_sequence')
    

    我的结果是(对于OS-X El-Capitan上的CPython):
    0.227491140366
    0.356791973114
    

    但是,pypy似乎更喜欢生成器的构造(我首先尝试my_xrangemy_sequence对其进行了尝试,并获得了相当一致的结果,尽管第一个运行似乎确实处于劣势-可能是由于JIT预热时间等):
    0.00285911560059
    0.00137305259705
    

    1在这里,我希望xrange具有优势-但同样,在您使用timeit之前,没有什么是正确的,然后只有在计时差异很大的情况下才是正确的,并且只有在执行计时的计算机上才是正确的。

    2请参阅免责声明:-P

    关于python - 为什么产量产生的发电机比xrange产生的发电机快?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38626308/

    10-12 16:55