usu*_* me 8 python memory set python-2.7
我使用%memit魔术函数来测量内存使用情况:
In [1]: %memit n = pow(10, 7); range(n)
peak memory: 568 MiB, increment: 272 MiB
In [2]: %memit n = pow(10, 7); set(xrange(n))
peak memory: 824 MiB, increment: 447 MiB
Run Code Online (Sandbox Code Playgroud)
好的,所以似乎有一个中间步骤,其中xrange(n)实例化为完整列表.但是,如果我将列表分成10个子列表,并将它们逐个联合起来呢?这会更有效,对吧?
In [3]: %memit n = pow(10, 7); reduce(set.union, (set(xrange(p, n, 10)) for p in range(10)))
peak memory: 1260 MiB, increment: 897 MiB
Run Code Online (Sandbox Code Playgroud)
嗯,这没有按预期进行.为什么这种reduce方法消耗的内存比set(xrange(n))?
有很多误解需要澄清。首先,a在变成in之前并没有xrange变成列表!setset(xrange(n))
该方法的峰值内存reduce来自于set.union返回一个新值,该新值是 2 个结果集的并集。并reduce在内部存储一个额外的值,即accum_value. 所以在该循环的最后一次迭代中for:
accum_value = function(accum_value, x)\nRun Code Online (Sandbox Code Playgroud)\n\naccum_value进入函数的 包含 10\xe2\x81\xb7 元素的 90%,包含x10\xe2\x81\xb7 元素的 10%,但返回值将需要所有 10\xe2\x81\xb7 元素的空间。所有这些都需要同时预留空间。只有在function返回之后,旧的内存才会accum_value被x释放。
然而这还没有结束。峰值内存确实表明进程中需要多少内存,但不表明之后使用了多少内存(如果该集合仍然存在)
\n\n因此需要一个不同的基准:
\n\nIn [1]: %memit n = pow(10, 7); result = set(xrange(n));\npeak memory: 522.22 MiB, increment: 498.93 MiB\nIn [2]: %memit 42\npeak memory: 513.83 MiB, increment: 0.12 MiB\nIn [3]: import sys\nIn [4]: sys.getsizeof(result)\nOut[4]: 268435688\nRun Code Online (Sandbox Code Playgroud)\n\n和
\n\nIn [1]: %memit n = pow(10, 7); result = reduce(set.union, (set(xrange(p, n, 10)) for p in range(10)));\npeak memory: 1063.20 MiB, increment: 1039.71 MiB\nIn [2]: %memit 42\npeak memory: 779.77 MiB, increment: 0.00 MiB\nIn [3]: import sys \nIn [4]: sys.getsizeof(result)\nOut[4]: 536871144\nIn [5]: 536871144.0 / 268435688\nOut[5]: 1.9999991357333977\nRun Code Online (Sandbox Code Playgroud)\n\n因此执行后内存使用量下降reduce 到778 MiB;然而,它仍然比更简单的集合构造情况要复杂。正如您所看到的,set(xrange(n))不需要太多内存,因为在构建集合后内存使用量仅下降了 9 MiB。
最值得注意的是,这种方法不仅reduce速度较慢,而且速度也较慢。结果集也消耗两倍的内存。这是因为一个集合是由哈希表支持的,只要认为它有太多冲突,它就会变得更大。您遇到过病态行为,即一组相同的值导致一个值占用另一个值两倍的内存。
| 归档时间: |
|
| 查看次数: |
134 次 |
| 最近记录: |