Есть много неправильных представлений, которые необходимо очистить. Прежде всего, xrange
не превращен в список, прежде чем он превращается в set
в set(xrange(n))
!
пик память для reduce
подхода исходит из того, что set.union
возвращает значение нового, который представляет собой объединение 2 наборов результатов. И reduce
внутренне хранит дополнительное значение, accum_value
. Так что на последней итерации этого for
цикла:
accum_value = function(accum_value, x)
accum_value
, который входит в функции содержит 90% 10⁷ элементов, x
содержит 10% 10⁷ элементов, но возвращаемое значение будет нужно пространство для всех 10⁷ элементов , Пространство для всех этих нужно резервировать одновременно. Только после того, как возвращается function
, выдается память для старых 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 МиБ после исполнения; однако это еще больше, чем для более простого случая построения множества. И, как вы можете видеть, set(xrange(n))
не нуждается в большой внутренней памяти, так как использование памяти падает всего на 9 миллионов после того, как набор был сконструирован.
В частности, не только приближается подход reduce
; итоговый набор потребляет вдвое больше памяти. Это связано с тем, что набор поддерживается хеш-таблицей, и он становится более крупным, когда считается, что он имеет слишком много конфликтов. Вы столкнулись с патологическим поведением, когда множество одинаковых значений приводит к тому, что в два раза больше памяти, чем в другом.
Вопросы, относящиеся: http://stackoverflow.com/questions/15198042/why-does-union-consume-more-memory-if-the-argument-is-a-set Обратите внимание, что 'set.union' будет использовать ** больше ** памяти, если аргумент является множеством, потому что он предполагает, что будет мало общих элементов и, следовательно, он будет выделять вдвое больше необходимой памяти. – Bakuriu