Chciałbym użyć tablicy numpy w pamięci współdzielonej do użytku z modułem wieloprocesorowym. Trudność polega na używaniu go jako tablicy numpy, a nie tylko jako tablicy 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]
Daje to wyniki takie jak:
Originally, the first two elements of arr = [0.3518653236697369, 0.517794725524976]
Now, the first two elements of arr = [-0.3518653236697369, 0.517794725524976]
Dostęp do tablicy można uzyskać w sposób ctypes, np arr[i]
. to sens. Jednak nie jest to tablica numpy i nie mogę wykonywać takich operacji, jak -1*arr
, lub arr.sum()
. Przypuszczam, że rozwiązaniem byłoby przekonwertowanie tablicy ctypes na tablicę numpy. Jednak (poza tym, że nie mogę tego zrobić), nie sądzę, aby był on już udostępniany.
Wydaje się, że byłoby standardowe rozwiązanie tego, co musi być powszechnym problemem.
python
numpy
multiprocessing
shared
Ian Langmore
źródło
źródło
subprocess
raczej niżmultiprocessing
.Odpowiedzi:
Aby dodać do odpowiedzi @ unutbu (już niedostępnych) i @Henry Gomersall. Możesz użyć
shared_arr.get_lock()
do zsynchronizowania dostępu w razie potrzeby:Przykład
Jeśli nie potrzebujesz zsynchronizowanego dostępu lub tworzysz własne blokady,
mp.Array()
jest to niepotrzebne. Możesz użyćmp.sharedctypes.RawArray
w tym przypadku.źródło
count
donumpy.frombuffer()
. Możesz spróbować zrobić to na niższym poziomie, używającmmap
lub czegoś podobnegoposix_ipc
bezpośrednio do zaimplementowania skalowalnego analogu RawArray (może to obejmować kopiowanie podczas zmiany rozmiaru) (lub poszukaj istniejącej biblioteki). Lub jeśli twoje zadanie na to pozwala: skopiuj dane w częściach (jeśli nie potrzebujesz wszystkich naraz). „Jak zmienić rozmiar pamięci współdzielonej” to osobne pytanie.Pool()
określa liczbę procesów (domyślnie używana jest liczba dostępnych rdzeni procesora).M
to liczba wywołańf()
funkcji.Z
Array
obiektem jestget_obj()
skojarzona metoda, która zwraca tablicę ctypes, która przedstawia interfejs bufora. Myślę, że następujące elementy powinny działać ...Po uruchomieniu wypisuje pierwszy element z
a
obecnie 10.0, pokazująca
ib
są tylko dwoma widokami w tej samej pamięci.Aby upewnić się, że nadal jest bezpieczny dla wielu procesorów, uważam, że będziesz musiał użyć
acquire
release
metod i istniejących naArray
obiekciea
, a także jego wbudowanego zamka, aby upewnić się, że wszystko jest bezpiecznie dostępne (chociaż nie jestem ekspertem w moduł wieloprocesorowy).źródło
mp.Array
.Chociaż już podane odpowiedzi są dobre, istnieje znacznie łatwiejsze rozwiązanie tego problemu, pod warunkiem spełnienia dwóch warunków:
W tym przypadku nie musisz majstrować przy jawnym udostępnianiu zmiennych, ponieważ procesy potomne zostaną utworzone za pomocą rozwidlenia. Rozwidlone dziecko automatycznie dzieli przestrzeń pamięci rodzica. W kontekście wieloprocesorowości Pythona oznacza to, że udostępnia on wszystkie zmienne na poziomie modułu ; zwróć uwagę, że nie dotyczy to argumentów, które jawnie przekazujesz swoim procesom potomnym lub funkcjom, które wywołujesz w pliku
multiprocessing.Pool
.Prosty przykład:
źródło
Napisałem mały moduł Pythona, który używa pamięci współdzielonej POSIX do udostępniania tablic numpy między interpreterami Pythona. Może uznasz to za przydatne.
https://pypi.python.org/pypi/SharedArray
Oto jak to działa:
źródło
Możesz skorzystać z
sharedmem
modułu: https://bitbucket.org/cleemesser/numpy-sharedmemOto twój oryginalny kod, tym razem wykorzystujący pamięć współdzieloną, która zachowuje się jak tablica NumPy (zwróć uwagę na dodatkową ostatnią instrukcję wywołującą funkcję NumPy
sum()
):źródło