Ci sono molti equivoci da chiarire. Prima di tutto, un xrange
è non trasformato in un elenco prima che sia trasformato in un set
in set(xrange(n))
!
La memoria picco per l'approccio reduce
deriva dal fatto che set.union
restituisce un valore nuova che è un'unione dei 2 set di risultati. E reduce
memorizza internamente un valore aggiuntivo, il accum_value
. Così sull'ultima iterazione di tale for
ciclo:
accum_value = function(accum_value, x)
Il accum_value
che va nella funzione contiene 90% di 10⁷ elementi, x
contiene 10% di 10⁷ elementi, ma il valore restituito sarà necessario spazio per tutti 10⁷ elementi . Lo spazio per tutti questi deve essere prenotato contemporaneamente. Solo dopo che function
è stato restituito, viene rilasciata la memoria per il vecchio accum_value
e x
.
Tuttavia questa non è ancora la fine. La memoria di picco indica la quantità di memoria necessaria in nel processo, ma non quanto è in uso dopo l'operazione completata se il set era ancora esistente.
Così un benchmark differente è necessario:
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
e
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
Quindi l'utilizzo della memoria per la reduce
scende a 778 MiB dopo l'esecuzione; tuttavia è ancora più che per il caso di costruzione di set più semplice. E come potete vedere, lo set(xrange(n))
non ha bisogno di molta memoria interna, poiché l'utilizzo della memoria diminuisce di appena 9 MiB dopo che il set è stato costruito.
In particolare, non solo l'approccio reduce
è più lento; il set risultante consuma anche il doppio della memoria. Questo perché un set è supportato da un hashtable e viene ingrandito ogni volta che si ritiene che abbia troppe collisioni. Hai incontrato un comportamento patologico in cui l'insieme degli stessi valori si traduce in uno che occupa il doppio della memoria dell'altro.
Domanda correlata: http://stackoverflow.com/questions/15198042/why-does-union-consume-more-memory-if-the-argument-is-a-set Nota che 'set.union' userà ** più ** memoria se l'argomento è un insieme, perché presuppone che ci saranno pochi elementi comuni e quindi assegnerà il doppio della memoria necessaria. – Bakuriu