![](/img/trans.png)
[英]Is memory usage better with One Big Process or many small Processes?
[英]Memory usage: creating one big set vs merging many small sets
我使用%memit
magic函數來測量內存使用情況:
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
好的,所以似乎有一個中間步驟,其中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
嗯,這沒有按預期進行。 為什么reduce
方法比set(xrange(n))
消耗更多內存?
根據文檔 , reduce
大致相當於:
def reduce(function, iterable, initializer=None):
it = iter(iterable)
if initializer is None:
try:
initializer = next(it)
except StopIteration:
raise TypeError('reduce() of empty sequence with no initial value')
accum_value = initializer
for x in it:
accum_value = function(accum_value, x)
return accum_value
迭代iterable
, (set(xrange(p, n, 10)) for p in range(10))
,需要大約447 MiB。 您可能會認為,由於此iterable是生成器表達式,因此您將節省內存,但整數將保存在內部空閑列表中 :
“為了速度”,Python維護整數對象的內部空閑列表。 不幸的是,這個免費清單既是不朽的,也是無限的。
因此,一旦每個集都被實例化,它消耗的大部分內存永遠不會被釋放。
返回值accum_value
也需要大約447 MiB。 因此, reduce
呼叫大約需要447 + 447 = 894 MiB。
有許多誤解需要澄清。 首先, xrange
在被set
為set(xrange(n))
之前不會變成列表!
reduce
方法的峰值內存來自set.union
返回一個新值的事實,該值是2個結果集的並集。 並且reduce
內部存儲額外的值,即accum_value
。 所以在for
循環的最后一次迭代中:
accum_value = function(accum_value, x)
進入函數的accum_value
包含90%的accum_value
元素, x
包含10%的10⁷元素,但返回值將需要所有10⁷元素的空間。 所有這些空間需要同時保留。 只有在function
返回后accum_value
釋放舊的accum_value
和x
的內存。
然而,這還不是結束。 峰值內存並告訴了多少內存所需的過程中 ,但不能是多少在使用后所完成的操作,如果集顯仍然存在。
因此需要一個不同的基准:
In [1]: %memit n = pow(10, 7); result = set(xrange(n));
peak memory: 522.22 MiB, increment: 498.93 MiB
In [2]: %memit 42
peak memory: 513.83 MiB, increment: 0.12 MiB
In [3]: import sys
In [4]: sys.getsizeof(result)
Out[4]: 268435688
和
In [1]: %memit n = pow(10, 7); result = reduce(set.union, (set(xrange(p, n, 10)) for p in range(10)));
peak memory: 1063.20 MiB, increment: 1039.71 MiB
In [2]: %memit 42
peak memory: 779.77 MiB, increment: 0.00 MiB
In [3]: import sys
In [4]: sys.getsizeof(result)
Out[4]: 536871144
In [5]: 536871144.0 / 268435688
Out[5]: 1.9999991357333977
因此,執行后, reduce
的內存使用量降至 778 MiB; 然而,它仍然不僅僅是更簡單的集合構造案例。 正如您所看到的, set(xrange(n))
不需要太多的內部存儲器,因為在構造集合之后內存使用量僅下降了9 MiB。
最值得注意的是, reduce
方法不僅更慢; 結果集也消耗了兩倍的內存 。 這是因為一個集合由一個哈希表支持,並且只要認為它有太多的沖突就會變得更大。 你遇到了病態行為,其中一組相同的值導致一個內存占另一個內存的兩倍。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.