Numpy vs. multiprocesamiento y mmap

Estoy utilizando el módulo de multiprocessing de Python para procesar grandes matrices numpy en paralelo. Los arreglos se asignan en memoria usando numpy.load(mmap_mode='r') en el proceso maestro. Después de eso, multiprocessing.Pool() divide el proceso (supongo).

Todo parece funcionar bien, excepto que estoy recibiendo líneas como:

 AttributeError("'NoneType' object has no attribute 'tell'",) in `` ignored 

en los registros de unittest. Las pruebas pasan bien, sin embargo.

¿Alguna idea de lo que está pasando allí?

Utilizando Python 2.7.2, OS X, NumPy 1.6.1.


ACTUALIZAR:

Después de una cierta depuración, busqué la causa en una ruta de código que estaba usando (una pequeña porción de) esta matriz numpy asignada en memoria como entrada a una llamada Pool.imap .

Al parecer, el “problema” es con la forma en que multiprocessing.Pool.imap pasa su entrada a los nuevos procesos: utiliza pickle. Esto no funciona con matrices numpy de mmap ed, y algo dentro de los cortes que lleva al error.

Encontré esta respuesta de Robert Kern que parece abordar el mismo problema. Sugiere crear una ruta de código especial para cuando la entrada de imap provenga de una matriz asignada en memoria: asigne en memoria la misma matriz manualmente en el proceso generado.

Esto sería tan complicado y feo que preferiría vivir con el error y las copias de memoria extra. ¿Hay alguna otra forma que sea más ligera al modificar el código existente?

Mi enfoque habitual (si puede vivir con copias de memoria adicionales) es hacer todo el IO en un proceso y luego enviar las cosas a un grupo de subprocesos de trabajo. Para cargar una porción de una matriz memmapped en la memoria, simplemente haga x = np.array(data[yourslice]) ( data[yourslice].copy() realidad no hace esto, lo que puede generar cierta confusión).

En primer lugar, vamos a generar algunos datos de prueba:

 import numpy as np np.random.random(10000).tofile('data.dat') 

Puedes reproducir tus errores con algo como esto:

 import numpy as np import multiprocessing def main(): data = np.memmap('data.dat', dtype=np.float, mode='r') pool = multiprocessing.Pool() results = pool.imap(calculation, chunks(data)) results = np.fromiter(results, dtype=np.float) def chunks(data, chunksize=100): """Overly-simple chunker...""" intervals = range(0, data.size, chunksize) + [None] for start, stop in zip(intervals[:-1], intervals[1:]): yield data[start:stop] def calculation(chunk): """Dummy calculation.""" return chunk.mean() - chunk.std() if __name__ == '__main__': main() 

Y si simplemente np.array(data[start:stop]) a producir np.array(data[start:stop]) lugar, solucionarás el problema:

 import numpy as np import multiprocessing def main(): data = np.memmap('data.dat', dtype=np.float, mode='r') pool = multiprocessing.Pool() results = pool.imap(calculation, chunks(data)) results = np.fromiter(results, dtype=np.float) def chunks(data, chunksize=100): """Overly-simple chunker...""" intervals = range(0, data.size, chunksize) + [None] for start, stop in zip(intervals[:-1], intervals[1:]): yield np.array(data[start:stop]) def calculation(chunk): """Dummy calculation.""" return chunk.mean() - chunk.std() if __name__ == '__main__': main() 

Por supuesto, esto hace una copia extra en memoria de cada fragmento.

A la larga, es probable que encuentre que es más fácil cambiar los archivos de memmap y pasar a algo como HDF. Esto es especialmente cierto si sus datos son multidimensionales. ( h5py , pero pyTables está bien si sus datos son “similares a una tabla”).

¡Buena suerte, al menos!