dog*_*ang 5 python sum generator python-internals
首先,我想测试生成器和列表理解之间的内存使用情况.本书给了我一个小小的代码片段,我在我的PC上运行它(python3.6,Windows),发现一些意想不到的东西.
FOllowing是我的代码,它不满足以前的意见(在sum函数中).
import tracemalloc
from time import time
def timeIt(func):
start = time()
func()
print('%s use time' % func.__name__, time() - start)
return func
tracemalloc.start()
numbers = range(1, 1000000)
@timeIt
def lStyle():
return sum([i for i in numbers if i % 3 == 0])
@timeIt
def gStyle():
return sum((i for i in numbers if i % 3 == 0))
lStyle()
gStyle()
shouldSize = [i for i in numbers if i % 3 == 0]
snapshotL = tracemalloc.take_snapshot()
top_stats = snapshotL.statistics('lineno')
print("[ Top 10 ]")
for stat in top_stats[:10]:
print(stat)
Run Code Online (Sandbox Code Playgroud)
输出:
lStyle use time 0.4460000991821289
gStyle use time 0.6190001964569092
[ Top 10 ]
F:/py3proj/play.py:31: size=11.5 MiB, count=333250, average=36 B
F:/py3proj/play.py:33: size=448 B, count=1, average=448 B
F:/py3proj/play.py:22: size=136 B, count=1, average=136 B
F:/py3proj/play.py:17: size=136 B, count=1, average=136 B
F:/py3proj/play.py:14: size=76 B, count=2, average=38 B
F:/py3proj/play.py:8: size=34 B, count=1, average=34 B
Run Code Online (Sandbox Code Playgroud)
两点:
我想也许sum函数做了我不知道的事情.谁能解释一下?
这本书是High Perfoamance Python.chapter 5.但我确实做了一些与本书不同的检查其他背景下的有效性.而他的代码在这里是book_code,他没有把列表理解放在总和函数中.
当谈到时间性能测试时,我确实依赖该timeit
模块,因为它会自动执行多次运行代码。
在我的系统上,timeit 给出以下结果(由于多次运行,我大大减小了大小):
>>> timeit.timeit("sum([i for i in numbers if i % 3 == 0])", "numbers = range(1, 1000)")
59.54427594248068
>>> timeit.timeit("sum((i for i in numbers if i % 3 == 0))", "numbers = range(1, 1000)")
64.36398425334801
Run Code Online (Sandbox Code Playgroud)
因此生成器速度慢了大约 8% (*)。这并不令人意外,因为生成器必须动态执行一些代码才能获取下一个值,而预先计算的列表仅增加其当前指针。
恕我直言,内存评估更复杂,所以我使用了来自 activestate 的对象及其内容的计算内存占用(Python 配方)
>>> numbers = range(1, 100)
>>> numbers = range(1, 100000)
>>> l = [i for i in numbers if i % 3 == 0]
>>> g = (i for i in numbers if i % 3 == 0)
>>> total_size(l)
1218708
>>> total_size(g)
88
>>> total_size(numbers)
48
Run Code Online (Sandbox Code Playgroud)
我的解释是,列表将内存用于其所有项目(这并不奇怪),而生成器只需要很少的值和一些代码,因此生成器的内存占用要少得多。
我强烈认为您已将其用于tracemalloc
不该用于的用途。它的目的是搜索可能的内存泄漏(大块内存从未被释放),而不是控制单个对象使用的内存。
注意:我只能测试小尺寸。但对于非常大的大小,列表可能会耗尽可用内存,并且机器将使用交换中的虚拟内存。在这种情况下,列表版本会变得慢很多。那里有更多详细信息