Pamięć współdzielona w wieloprocesorze
Mam trzy duże listy. Pierwszy zawiera bitarrays (moduł bitarray 0.8.0), a dwa pozostałe zawierają tablice liczb całkowitych.
l1=[bitarray 1, bitarray 2, ... ,bitarray n]
l2=[array 1, array 2, ... , array n]
l3=[array 1, array 2, ... , array n]
Te struktury danych zajmują sporo pamięci RAM (łącznie~16GB).
Jeśli uruchomię 12 podprocesów używając:
multiprocessing.Process(target=someFunction, args=(l1,l2,l3))
Czy to oznacza, że l1, l2 i l3 będą kopiowane dla każdego podprocesu, czy też podprocesy będą współdzielić te listy? Czy aby być bardziej bezpośrednim, będę używał 16GB lub 192GB pamięci RAM?
SomeFunction odczyta wartości z te listy, a następnie wykonuje pewne obliczenia na podstawie odczytanych wartości. Wyniki zostaną zwrócone do procesu macierzystego. Listy l1, l2 i l3 nie będą modyfikowane przez jakąś funkcję.
Dlatego zakładam, że podprocesy nie potrzebują i nie kopiują tych ogromnych list, ale zamiast tego po prostu dzielą się nimi z rodzicem. To znaczy, że program zajmie 16GB PAMIĘCI RAM (niezależnie od tego, ile podprocesów uruchomię) ze względu na podejście copy-on-write pod Linuksem? Czy ja poprawne czy brakuje mi czegoś, co mogłoby spowodować skopiowanie list?
EDIT : Nadal jestem zdezorientowany, po przeczytaniu trochę więcej na ten temat. Z jednej strony Linux używa funkcji copy-on-write, co powinno oznaczać, że żadne dane nie są kopiowane. Z drugiej strony, dostęp do obiektu zmieni jego liczbę ref-count (nadal Nie wiem dlaczego i co to oznacza). Mimo to, czy cały obiekt zostanie skopiowany?
Na przykład, jeśli zdefiniuję jakąś funkcję w następujący sposób:
def someFunction(list1, list2, list3):
i=random.randint(0,99999)
print list1[i], list2[i], list3[i]
Używałby funkcja ta oznacza, że l1, l2 i l3 będą kopiowane w całości dla każdego podprocesu?
Czy można to sprawdzić?EDIT2 po przeczytaniu nieco więcej i monitorowaniu całkowitego wykorzystania pamięci systemu podczas uruchamiania podprocesów, wydaje się, że całe obiekty są rzeczywiście kopiowane dla każdego podprocesu. I wydaje się, że to dlatego, że liczenie referencji.
Liczenie referencji dla l1, l2 i l3 jest w moim programie zbędne. Dzieje się tak dlatego, że l1, l2 i l3 zostanie zachowana w pamięci (bez zmian) do momentu zakończenia procesu nadrzędnego. Do tego czasu nie ma potrzeby zwalniania pamięci używanej przez te listy. W zasadzie wiem na pewno, że liczba referencji pozostanie powyżej 0 (dla tych list i każdego obiektu z tych list) dopóki program się nie zakończy.
Więc teraz pojawia się pytanie, Jak mogę się upewnić, że obiekty nie zostaną skopiowane do każdego pod-procesu? Czy Mogę wyłączyć zliczanie referencji dla tych list i każdego obiektu w tych listy?
EDIT3 tylko dodatkowa uwaga. Podprocesy nie muszą modyfikować l1
, l2
i l3
lub dowolne obiekty z tych list. Podprocesy muszą tylko być w stanie odwołać się do niektórych z tych obiektów bez powodowania kopiowania pamięci dla każdego podprocesu.
3 answers
Ogólnie rzecz biorąc, istnieją dwa sposoby udostępniania tych samych danych:
- wielowątkowość
- pamięć Dzielona
Wielowątkowość Pythona nie nadaje się do zadań związanych z procesorem (ze względu na Gil), więc zwyczajowym rozwiązaniem w tym przypadku jest kontynuowanie multiprocessing
. Jednak dzięki temu rozwiązaniu musisz jawnie udostępniać dane, używając multiprocessing.Value
oraz multiprocessing.Array
.
Zauważ, że zazwyczaj dzielenie się danymi między procesami może nie być najlepszym wyborem, ze względu na wszystkie problemy z synchronizacją; podejście obejmujące aktorów wymieniających wiadomości jest zwykle postrzegane jako lepszy wybór. Zobacz także dokumentacja Pythona :
Jak wspomniano powyżej, podczas programowania współbieżnego Zwykle najlepiej unikać używania współdzielonego stanu w miarę możliwości. To jest szczególnie prawdziwe podczas korzystania z wielu procesów.
Jednakże, jeśli naprawdę potrzebujesz użyć niektórych udostępnionych danych, to multiprocessing zapewnia kilka sposobów na więc.
W Twoim przypadku, musisz zawinąć l1
, l2
i l3
w jakiś sposób zrozumiałe przez multiprocessing
(np. przez użycie multiprocessing.Array
), a następnie przekazać je jako parametry.
Zauważ również, że, jak powiedziałeś, nie potrzebujesz dostępu do zapisu, wtedy powinieneś przekazać lock=False
podczas tworzenia obiektów, w przeciwnym razie cały dostęp będzie nadal serializowany.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-04 07:48:52
Jeśli chcesz skorzystać z funkcji Kopiuj przy zapisie, a Twoje dane są statyczne ( niezmienione w procesach potomnych) - powinieneś sprawić, aby python nie mieszał się z blokami pamięci, w których leżą Twoje dane. Możesz to łatwo zrobić, używając struktur C lub c++ (na przykład stl) jako kontenerów i dostarczając własne wrappery Pythona, które będą używać wskaźników do pamięci danych (lub ewentualnie kopiować dane mem), gdy obiekt na poziomie Pythona zostanie utworzony, jeśli w ogóle. Wszystko to można zrobić bardzo łatwo z niemal prostotą i składnia z cython .
# pseudo cython cdef class FooContainer: cdef char * data def __cinit__(self, char * foo_value): self.data = malloc(1024, sizeof(char)) memcpy(self.data, foo_value, min(1024, len(foo_value))) def get(self): return self.data
# python part from foo import FooContainer f = FooContainer("hello world") pid = fork() if not pid: f.get() # this call will read same memory page to where # parent process wrote 1024 chars of self.data # and cython will automatically create a new python string # object from it and return to caller
Powyższy pseudo-kod jest źle napisany. Nie używaj go. W miejsce siebie.dane powinny być w Twoim przypadku kontenerem C lub c++.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-03 19:41:34
Możesz użyć memcached lub redis i ustawić każdy jako parę wartości klucza {"l1",},..
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-01 11:58:47