2011-01-20 11 views
8

Ho fatto alcuni parametri di riferimento di base di prestazioni e consumo di memoria e mi chiedevo se c'è un modo per rendere le cose ancora più veloce ...Blocco gratuito di sola lettura Elenco in Python?

  1. Ho un gigantesco elenco di 70.000 elemento con un ndarray numpy, e il percorso del file in una tupla nella suddetta lista.

  2. La mia prima versione passò una copia a fette di lista per ciascuno dei processi in modulo python multiprocesso, ma sarebbe esploso l'utilizzo della RAM a più di 20 + Gigabyte

  3. La seconda versione ho spostato nella spazio globale e accedervi tramite indice come foo [i] in un ciclo in ciascuno dei miei processi che sembra metterlo in una semantica di area di memoria/semantica condivisa con i processi in modo da non esplodere l'utilizzo della memoria (rimane a ~ 3 Gigabyte)

  4. Tuttavia, in base ai benchmark/traccia delle prestazioni, sembra che la maggior parte del tempo di applicazione venga ora utilizzata per "acquisire" modalità ...

Così mi chiedevo se non v'è alcun modo che posso in qualche modo trasformare questa lista in una sorta di lockfree/lettura solo in modo che io possa fare via con parte della fase di acquisire per contribuire ad accelerare accedi ancora di più.

Edit 1: Ecco la top poche uscita di linea della profilatura delle app

ncalls tottime percall cumtime percall filename:lineno(function) 
    65 2450.903 37.706 2450.903 37.706 {built-in method acquire} 
39320 0.481 0.000 0.481 0.000 {method 'read' of 'file' objects} 
    600 0.298 0.000 0.298 0.000 {posix.waitpid} 
    48 0.271 0.006 0.271 0.006 {posix.fork} 

Edit 2: Ecco un esempio della struttura della lista:

# Sample code for a rough idea of how the list is constructed 
sim = [] 
for root, dirs, files in os.walk(rootdir): 
    path = os.path.join(root, filename) 
    image= Image.open(path) 
    np_array = np.asarray(image) 
    sim.append((np_array, path)) 

# Roughly it would look something like say this below 
sim = List((np.array([[1, 2, 3], [4, 5, 6]], np.int32), "/foobar/com/what.something")) 

Quindi d'ora in poi l'elenco SIM deve essere letto solo

risposta

10

Il modulo multiprocessing fornisce esattamente ciò che è necessario: un array condiviso con blocco opzionale, ovvero la classe multiprocessing.Array. Passa al costruttore lock=False per disabilitare il blocco.

Modifica (tenendo conto dell'aggiornamento): le cose sono in realtà molto più complesse di quanto inizialmente mi aspettassi. I dati di tutti gli elementi del tuo elenco devono essere creati nella memoria condivisa. Se si inserisce la lista stessa (cioè i puntatori ai dati effettivi) nella memoria condivisa, non importa troppo perché questo dovrebbe essere un piccolo rispetto ai dati di tutti i file. Per memorizzare i dati dei file in memoria condivisa, utilizzare

shared_data = multiprocessing.sharedctypes.RawArray("c", data) 

dove data è i dati letti dal file. Per utilizzare questo come una matrice NumPy in uno dei processi, utilizzare

numpy.frombuffer(shared_data, dtype="c") 

che creerà una vista matrice NumPy per i dati condivisi. Allo stesso modo, di mettere il nome del percorso nella memoria condivisa, utilizzare

shared_path = multiprocessing.sharedctypes.RawArray("c", path) 

dove path è una stringa Python ordinario. Nei tuoi processi, puoi accedere a questo come una stringa Python usando shared_path.raw. Ora aggiungi (shared_data, shared_path) al tuo elenco. L'elenco verrà copiato negli altri processi, ma i dati effettivi no.

Inizialmente intendevo utilizzare un multiprocessing.Array per l'elenco effettivo. Ciò sarebbe perfettamente possibile e garantirebbe che anche la lista stessa (cioè i puntatori ai dati) sia nella memoria condivisa. Ora penso che questo non sia affatto importante, purché i dati reali siano condivisi.

+0

Il mio problema è che ho bisogno di un modo per memorizzare un ndarray + filepath numpy. La mia comprensione della roba di Array è che memorizza solo 1 elemento, ad esempio 'c' non può memorizzare "char" – Pharaun

+0

@Pharaun: Forse non ho ottenuto correttamente la struttura dell'elenco. Potresti renderlo più esplicito nella tua domanda? Sono abbastanza sicuro che la classe 'Array' possa essere utilizzata per la tua applicazione. –

+0

@Sven, ho aggiornato la domanda di cui sopra con un campione approssimativo di come la lista è costruita sotto edit2 in modo da dare un'idea ... – Pharaun