Sto leggendo il documentation for Memory Management in Python C extensions e, per quanto posso dire, sembra che non ci siano molti motivi per utilizzare malloc
anziché PyMem_Malloc
. Supponiamo di voler allocare un array che non deve essere esposto al codice sorgente di Python e che verrà archiviato in un oggetto che sarà sottoposto a garbage collection. C'è qualche ragione per usare malloc
?C'è qualche ragione per usare malloc su PyMem_Malloc?
risposta
MODIFICA: correzioni PyMem_Malloc
e PyObject_Malloc
misti; sono due chiamate diverse.
Senza il PYMALLOC_DEBUG
macro attivato, PyMem_Malloc
è un alias di libc di malloc()
, avente un caso speciale: chiamata PyMem_Malloc
allocare byte zero restituirà un puntatore non NULL, mentre malloc (zero_bytes) potrebbero restituire un valore NULL o sollevare errore di sistema (source code reference):
/* malloc. Notare che nbytes == 0 tenta di restituire un puntatore non NULL, distinto * da tutti gli altri puntatori attualmente attivi. Questo potrebbe non essere possibile. */
Inoltre, v'è una nota consultivo per la pymem.h
header file:
Non mischiare mai chiamate a PyMem_ con chiamate verso la piattaforma di malloc/realloc/ calloc/libero.Ad esempio, su Windows DLL diverse possono finire con l'uso di diversi heap e se si utilizza PyMem_Malloc si ottiene la memoria dall'heap utilizzato dalla DLL Python ; potrebbe essere un disastro se si scarica direttamente ( ) direttamente nella propria estensione . L'utilizzo di PyMem_Free invece di assicura che Python possa restituire la memoria nell'heap corretto. Come altro esempio, in modalità PYMALLOC_DEBUG, Python avvolge tutte le chiamate a tutte le funzioni di memoria PyMem_ e PyObject_ in involucri speciali di debug che aggiungono informazioni aggiuntive di debug per blocchi di memoria dinamica. Le routine del sistema non hanno idea di cosa fare con quella roba, e i wrapper Python non hanno idea di cosa fare con blocchi grezzi ottenuti direttamente da quindi le routine di sistema.
Poi, ci sono alcune accordature specifiche Python all'interno
PyMem_Malloc
PyObject_Malloc
, una funzione utilizzata non solo per estensioni C, ma per tutte le allocazioni dinamiche durante l'esecuzione di un programma Python, come 100*234
, str(100)
o 10 + 4j
:
>>> id(10 + 4j)
139721697591440
>>> id(10 + 4j)
139721697591504
>>> id(10 + 4j)
139721697591440
Le precedenti istanze complex()
sono piccoli oggetti allocati su un pool dedicato.
piccoli oggetti (< 256 bytes) assegnazione con
PyMem_Malloc
PyObject_Malloc
è molto efficiente poiché è fatto da un pool di 8 byte blocchi allineati, una piscina per ciascuna dimensione del blocco esistente. Ci sono anche blocchi di Pages e Arenas per allocazioni maggiori.
Questo commento sul source code spiega come la chiamata PyObject_Malloc
è ottimizzato:
/*
* The basic blocks are ordered by decreasing execution frequency,
* which minimizes the number of jumps in the most common cases,
* improves branching prediction and instruction scheduling (small
* block allocations typically result in a couple of instructions).
* Unless the optimizer reorders everything, being too smart...
*/
piscine, Pages e Arenas sono ottimizzazioni volte a ridurre external memory fragmentation dei programmi Python esecuzione prolungata.
Verificare the source code per la documentazione dettagliata completa sugli interni di memoria di Python.
Dalla mia esperienza di scrittura di funzioni MATLAB .mex, penso che il fattore determinante più grande per l'utilizzo di malloc o meno sia la portabilità. Supponiamo che tu abbia un file di intestazione che esegue un carico di funzioni utili usando solo i tipi di dati interni (non c'è bisogno dell'interazione dell'oggetto Python, quindi nessun problema con l'uso di malloc) e all'improvviso ti accorgi di voler portare quel file di intestazione su un diverso codice che ha niente a che fare con Python (forse è un progetto scritto esclusivamente in C), usare malloc sarebbe ovviamente una soluzione molto più portabile.
Ma per il tuo codice che è puramente un'estensione Python, la mia reazione iniziale sarebbe di aspettarsi che la funzione nativa c funzioni più velocemente. Non ho prove per confermare questo :)
È normale aspettarsi che la funzione C nativa migliori. Il fatto è che sono entrambe funzioni native C. :-) –
Beh, immagino che siano ... bel tecnicismo :) Immagino di voler dire di più che mi aspetterei che il sistema di allocazione di memoria nativa di C sia più veloce di C nativo implementato per il sistema di allocazione di memoria di Python: P – William
Ho usato sia malloc che PyMem_Malloc. I miei benchmark hanno mostrato una differenza di prestazioni trascurabile tra i due. PyMem_Malloc potrebbe essere stato più veloce, ma non credo che la differenza fosse statisticamente rilevante. YMMV, ovviamente. – casevh
È perfettamente OK per le estensioni per allocare memoria con malloc o altri allocatori di sistema. Questo è normale e inevitabile per molti tipi di moduli: la maggior parte dei moduli che avvolgono altre librerie, che a loro volta non sanno nulla di Python, causerà allocazioni native quando si verificano all'interno di quella libreria. (Alcune librerie ti consentono di controllare l'allocazione in modo sufficiente per impedirlo, la maggior parte no.)
C'è un serio svantaggio nell'usare PyMem_Malloc: devi tenere il GIL quando lo usi. Le librerie native spesso desiderano rilasciare GIL quando eseguono calcoli intensivi della CPU o eseguono chiamate che potrebbero bloccare, come I/O. La necessità di bloccare il GIL prima delle allocazioni può essere da qualche parte tra un inconveniente e un problema di prestazioni.
L'utilizzo dei wrapper di Python per l'allocazione della memoria consente di utilizzare il codice di debug della memoria di Python. Con strumenti come Valgrind, tuttavia, dubito del valore del mondo reale.
Avrete bisogno di usare queste funzioni se l'API lo richiede; ad esempio, se viene passata un'API a un puntatore che deve essere allocato con queste funzioni, quindi può essere liberato con esse. Escludendo un motivo esplicito come quello per usarli, rimango con allocazione normale.
- 1. C'è qualche ragione per usare questo->
- 2. Qualche ragione importante per non usare AJAX?
- 3. C'è qualche ragione per non usare le proprietà 'protette'?
- 4. Qualche ragione per continuare a utilizzare CVS?
- 5. C'è qualche ragione per usare javac su groovyc in un progetto di codice misto?
- 6. C'è qualche ragione legittima per usare i socket Unix su TCP/IP con mysql?
- 7. Perché ho bisogno del gil per PyMem_Malloc()?
- 8. Che cosa utilizzare per l'hashing della password? Qualche ragione per non usare jBCrypt?
- 9. C'è qualche ragione per non usare UTF-8, 16, ecc. Per tutto?
- 10. È una buona ragione per usare alloca?
- 11. JS doppio punto esclamativo: c'è qualche buona ragione per usarlo?
- 12. C'è qualche ragione per NON usare src = "// dominio.com/file.js", che è il protocollo dinamico?
- 13. C'è qualche buona ragione per usare <rtexprvalue> false</ rtexprvalue> nei tag JSP?
- 14. C'è qualche ragione per usare le classi in Python se c'è una sola classe nel programma?
- 15. C'è qualche buona ragione per non usare unicode in contrasto con la stringa?
- 16. C'è qualche ragione per non usare HTTP PUT e DELETE in un'applicazione web?
- 17. C'è qualche ragione specifica per usare Amazon SNS invece del servizio diretto Baidu
- 18. c'è qualche plugin per usare git su gedit su ubuntu?
- 19. Qualche differenza tra malloc e Marshal.AllocHGlobal?
- 20. Qualche ragione per non schiaffeggiare la parola chiave 'sincronizzata' ovunque?
- 21. C'è qualche ragione per evitare il pattern sentinella in Java?
- 22. Quale può essere la ragione per usare la proprietà "controllerAs"?
- 23. Scala: può esserci qualche ragione per preferire `filter + map` su` collect`?
- 24. Qualche ragione per non fare un 301 su favicon.ico, apple-touch-icon e robots.txt?
- 25. C'è qualche buona ragione che non dovrei usare - (trattino) nei nomi dei campi in MySQL?
- 26. C'è mai una buona ragione per usare Insertion Sort?
- 27. C'è mai una buona ragione per usare eval()?
- 28. perché usare malloc con la struttura?
- 29. C'è qualche buona ragione per NON usare un ViewComponent invece di una Vista parziale in MVC principale?
- 30. C'è qualche situazione in cui devo usare .attr() su .prop()?
Gli allocatori nativi sono già estremamente ottimizzati. Questo non ha alcuna influenza sui moduli di estensione - se non altro, è solo un ulteriore sovraccarico per rallentare le cose. –
@Glenn Hai numeri difficili da sostenere? I documenti sono abbastanza estesi e dettagliati per essere solo un "overhead per rallentare le cose". – vz0
Ho esperienza e buon senso: l'allocatore di sistema influenza la velocità dell'intero sistema, quindi è necessario un grande sforzo per ottimizzarli. Se stai sostenendo che Python migliora su questo - per l'uso del modulo di estensione, non solo il caso speciale del core Python di basso livello - questa è la tua richiesta di backup. –