Ho un problema con la mia applicazione python, e penso che sia correlato alla garbage collection di Python, anche se non sono sicuro ...La garbage collection di Python può essere così lenta?
Il problema è che la mia applicazione impiega molto tempo per uscire e per passare a una funzione alla successiva.
Nella mia applicazione gestisco dizionari molto grandi, contenenti migliaia di oggetti di grandi dimensioni che vengono istanziati da classi C++ avvolte.
Ho inserito alcune uscite di timestamp nel mio programma, e ho visto che alla fine di ogni funzione, quando gli oggetti creati all'interno della funzione dovevano andare fuori campo, l'interprete impiega molto tempo prima di chiamare la funzione successiva . E osservo lo stesso problema alla fine dell'applicazione, quando il programma dovrebbe uscire: un sacco di tempo (~ ore!) È trascorso tra l'ultimo timestamp sullo schermo e l'aspetto del nuovo prompt.
L'utilizzo della memoria è stabile, quindi non ho perdite di memoria.
Qualche suggerimento?
Può essere la garbage collection di migliaia di oggetti C++ di grandi dimensioni che rallentano?
C'è un metodo per accelerare?
UPDATE:
Grazie mille per tutte le vostre risposte, mi ha dato un sacco di suggerimenti per eseguire il debug il mio codice :-)
io uso Python 2.6.5 su Scientific Linux 5, un distribuzione personalizzata basata su Red Hat Enterprise 5. E in realtà non sto usando SWIG per ottenere i binding Python per il nostro codice C++, ma il framework Reflex/PyROOT. Lo so, non è molto conosciuto al di fuori della fisica delle particelle (ma è ancora open source e disponibile gratuitamente) e devo usarlo perché è l'impostazione predefinita per il nostro framework principale.
E in questo contesto il comando DEL dal lato Python non funziona, l'avevo già provato. DEL elimina solo la variabile python collegata all'oggetto C++, non l'oggetto stesso in memoria, che è ancora di proprietà del lato C++ ...
... Lo so, non è standard, credo, e un po ' complicato, mi spiace :-P
Ma seguendo i tuoi suggerimenti, descriverò il mio codice e tornerò da te con ulteriori dettagli, come hai suggerito.
ULTERIORI UPDATE:
Ok, seguendo i vostri suggerimenti, ho il mio codice strumentato con cProfile
, e ho scoperto che in realtà la funzione gc.collect()
è la funzione prendendo la maggior parte del tempo in esecuzione !!
Qui l'uscita dal cProfile
+ pstats
print_stats():
>>> p.sort_stats("time").print_stats(20) Wed Oct 20 17:46:02 2010 mainProgram.profile 547303 function calls (542629 primitive calls) in 548.060 CPU seconds Ordered by: internal time List reduced from 727 to 20 due to restriction ncalls tottime percall cumtime percall filename:lineno(function) 4 345.701 86.425 345.704 86.426 {gc.collect} 1 167.115 167.115 200.946 200.946 PlotD3PD_v3.2.py:2041(PlotSamplesBranches) 28 12.817 0.458 13.345 0.477 PlotROOTUtils.py:205(SaveItems) 9900 10.425 0.001 10.426 0.001 PlotD3PD_v3.2.py:1973(HistoStyle) 6622 5.188 0.001 5.278 0.001 PlotROOTUtils.py:403(__init__) 57 0.625 0.011 0.625 0.011 {built-in method load} 103 0.625 0.006 0.792 0.008 dbutils.py:41(DeadlockWrap) 14 0.475 0.034 0.475 0.034 {method 'dump' of 'cPickle.Pickler' objects} 6622 0.453 0.000 5.908 0.001 PlotROOTUtils.py:421(CreateCanvas) 26455 0.434 0.000 0.508 0.000 /opt/root/lib/ROOT.py:215(__getattr__) [...] >>> p.sort_stats("cumulative").print_stats(20) Wed Oct 20 17:46:02 2010 mainProgram.profile 547303 function calls (542629 primitive calls) in 548.060 CPU seconds Ordered by: cumulative time List reduced from 727 to 20 due to restriction ncalls tottime percall cumtime percall filename:lineno(function) 1 0.001 0.001 548.068 548.068 PlotD3PD_v3.2.py:2492(main) 4 0.000 0.000 346.756 86.689 /usr/lib//lib/python2.5/site-packages/guppy/heapy/Use.py:171(heap) 4 0.005 0.001 346.752 86.688 /usr/lib//lib/python2.5/site-packages/guppy/heapy/View.py:344(heap) 1 0.002 0.002 346.147 346.147 PlotD3PD_v3.2.py:2537(LogAndFinalize) 4 345.701 86.425 345.704 86.426 {gc.collect} 1 167.115 167.115 200.946 200.946 PlotD3PD_v3.2.py:2041(PlotBranches) 28 12.817 0.458 13.345 0.477 PlotROOTUtils.py:205(SaveItems) 9900 10.425 0.001 10.426 0.001 PlotD3PD_v3.2.py:1973(HistoStyle) 13202 0.336 0.000 6.818 0.001 PlotROOTUtils.py:431(PlottingCanvases) 6622 0.453 0.000 5.908 0.001 /root/svn_co/rbianchi/SoftwareDevelopment [...] >>>
Quindi, in entrambe le uscite, scelte per "tempo" e da tempo "cumulativo", rispettivamente, gc.collect()
è la funzione che consumano la maggior parte del tempo di esecuzione del mio programma!:-P
E questa è l'uscita del profiler di memoria Heapy
, appena prima di restituire il programma main()
.
memory usage before return: Partition of a set of 65901 objects. Total size = 4765572 bytes. Index Count % Size % Cumulative % Kind (class/dict of class) 0 25437 39 1452444 30 1452444 30 str 1 6622 10 900592 19 2353036 49 dict of PlotROOTUtils.Canvas 2 109 0 567016 12 2920052 61 dict of module 3 7312 11 280644 6 3200696 67 tuple 4 6622 10 238392 5 3439088 72 0xa4ab74c 5 6622 10 185416 4 3624504 76 PlotROOTUtils.Canvas 6 2024 3 137632 3 3762136 79 types.CodeType 7 263 0 129080 3 3891216 82 dict (no owner) 8 254 0 119024 2 4010240 84 dict of type 9 254 0 109728 2 4119968 86 type Index Count % Size % Cumulative % Kind (class/dict of class) 10 1917 3 107352 2 4264012 88 function 11 3647 5 102116 2 4366128 90 ROOT.MethodProxy 12 148 0 80800 2 4446928 92 dict of class 13 1109 2 39924 1 4486852 93 __builtin__.wrapper_descriptor 14 239 0 23136 0 4509988 93 list 15 87 0 22968 0 4532956 94 dict of guppy.etc.Glue.Interface 16 644 1 20608 0 4553564 94 types.BuiltinFunctionType 17 495 1 19800 0 4573364 94 __builtin__.weakref 18 23 0 11960 0 4585324 95 dict of guppy.etc.Glue.Share 19 367 1 11744 0 4597068 95 __builtin__.method_descriptor
Qualche idea sul perché o su come ottimizzare la garbage collection?
C'è qualche controllo più dettagliato che posso fare?
"Qualche suggerimento?". Usa il profiler per ottenere più informazioni su dove viene speso il tempo. Pubblica i risultati come aggiornamento della tua domanda. –
@nos: In realtà, Python usa il refcounting, quindi verrà raccolto un oggetto * non referenziato. Il GC di Python è piuttosto semplice rispetto alle bestie intelligenti nelle buone JVM e in .NET. – delnan
@delnan per la precisione, l'implementazione di CPython ha quel comportamento. Mi sembra di ricordare alcune versioni sperimentali con algoritmi molto più elaborati. –