Eu gostaria de usar uma matriz numpy na memória compartilhada para uso com o módulo de multiprocessamento. A dificuldade é usá-lo como um array numpy, e não apenas como um array ctypes.
from multiprocessing import Process, Array
import scipy
def f(a):
a[0] = -a[0]
if __name__ == '__main__':
# Create the array
N = int(10)
unshared_arr = scipy.rand(N)
arr = Array('d', unshared_arr)
print "Originally, the first two elements of arr = %s"%(arr[:2])
# Create, start, and finish the child processes
p = Process(target=f, args=(arr,))
p.start()
p.join()
# Printing out the changed values
print "Now, the first two elements of arr = %s"%arr[:2]
Isso produz resultados como:
Originally, the first two elements of arr = [0.3518653236697369, 0.517794725524976]
Now, the first two elements of arr = [-0.3518653236697369, 0.517794725524976]
O array pode ser acessado de forma ctypes, por exemplo, arr[i]
faz sentido. No entanto, não é uma matriz numpy e não posso executar operações como -1*arr
, ou arr.sum()
. Suponho que uma solução seria converter a matriz ctypes em uma matriz numpy. Porém (além de não poder fazer esse trabalho), não acredito que seria mais compartilhado.
Parece que haveria uma solução padrão para o que deve ser um problema comum.
python
numpy
multiprocessing
shared
Ian Langmore
fonte
fonte
subprocess
vez demultiprocessing
.Respostas:
Para adicionar às respostas de @unutbu (não está mais disponível) e de @Henry Gomersall. Você pode usar
shared_arr.get_lock()
para sincronizar o acesso quando necessário:Exemplo
Se você não precisa de acesso sincronizado ou cria seus próprios bloqueios, então
mp.Array()
é desnecessário. Você poderia usarmp.sharedctypes.RawArray
neste caso.fonte
count
paranumpy.frombuffer()
. Você pode tentar fazer isso em um nível inferior usandommap
ou algo comoposix_ipc
diretamente para implementar um analógico do RawArray (pode envolver a cópia durante o redimensionamento) (ou procurar por uma biblioteca existente). Ou se sua tarefa permitir: copie os dados em partes (se não precisar de todos de uma vez). "Como redimensionar uma memória compartilhada" é uma boa pergunta à parte.Pool()
define o número de processos (o número de núcleos de CPU disponíveis é usado por padrão).M
é o número de vezes que af()
função é chamada.O
Array
objeto possui umget_obj()
método associado a ele, que retorna o array ctypes que apresenta uma interface de buffer. Acho que o seguinte deve funcionar ...Quando executado, ele imprime o primeiro elemento de
a
agora sendo 10.0, mostrandoa
eb
são apenas duas visualizações na mesma memória.Para ter certeza de que ele ainda é seguro para multiprocessadores, acredito que você terá que usar os métodos
acquire
erelease
existentes noArray
objetoa
, e seu bloqueio embutido para garantir que todos sejam acessados com segurança (embora eu não seja um especialista no módulo multiprocessador).fonte
mp.Array
.Embora as respostas já dadas sejam boas, há uma solução muito mais fácil para esse problema, desde que duas condições sejam atendidas:
Nesse caso, você não precisa se preocupar em tornar as variáveis explicitamente compartilhadas, pois os processos filhos serão criados usando um fork. Uma criança bifurcada compartilha automaticamente o espaço de memória dos pais. No contexto do multiprocessamento Python, isso significa que ele compartilha todas as variáveis de nível de módulo ; observe que isso não se aplica a argumentos que você passa explicitamente para seus processos filho ou para as funções que você chama em um
multiprocessing.Pool
ou outro.Um exemplo simples:
fonte
Eu escrevi um pequeno módulo python que usa memória compartilhada POSIX para compartilhar matrizes entorpecidas entre interpretadores python. Talvez você ache útil.
https://pypi.python.org/pypi/SharedArray
Funciona assim:
fonte
Você pode usar o
sharedmem
módulo: https://bitbucket.org/cleemesser/numpy-sharedmemAqui está seu código original, desta vez usando memória compartilhada que se comporta como uma matriz NumPy (observe a última instrução adicional que chama uma
sum()
função NumPy ):fonte