Poznanie wieloprocesorowości w Pythonie (z artykułu PMOTW ) i chciałbym uzyskać wyjaśnienie, co dokładnie join()
robi ta metoda.
W starym samouczku z 2008 roku stwierdza się, że bez p.join()
wywołania w poniższym kodzie „proces potomny będzie siedział bezczynnie i nie zostanie zakończony, stając się zombie, którego należy ręcznie zabić”.
from multiprocessing import Process
def say_hello(name='world'):
print "Hello, %s" % name
p = Process(target=say_hello)
p.start()
p.join()
Dodałem wydruk PID
, a także time.sleep
do badania i ile mogę powiedzieć tego, zakończone jest proces na własną rękę:
from multiprocessing import Process
import sys
import time
def say_hello(name='world'):
print "Hello, %s" % name
print 'Starting:', p.name, p.pid
sys.stdout.flush()
print 'Exiting :', p.name, p.pid
sys.stdout.flush()
time.sleep(20)
p = Process(target=say_hello)
p.start()
# no p.join()
w ciągu 20 sekund:
936 ttys000 0:00.05 /Library/Frameworks/Python.framework/Versions/2.7/Reso
938 ttys000 0:00.00 /Library/Frameworks/Python.framework/Versions/2.7/Reso
947 ttys001 0:00.13 -bash
po 20 sekundach:
947 ttys001 0:00.13 -bash
Zachowanie jest takie samo w przypadku p.join()
dodania z powrotem na końcu pliku. Python Module of the Week oferuje bardzo czytelne wyjaśnienie modułu ; „Aby poczekać, aż proces zakończy swoją pracę i zakończy pracę, użyj metody join ().”, Ale wygląda na to, że przynajmniej OS X to robił.
Zastanawiam się też nad nazwą metody. Czy .join()
metoda coś tutaj łączy? Czy łączy proces z jego zakończeniem? A może po prostu ma taką samą nazwę jak natywna .join()
metoda Pythona ?
źródło
CPU, Memory resources
są oddzielane od procesu nadrzędnego, a następniejoin
ponownie odsyłane po zakończeniu procesu potomnego?Odpowiedzi:
join()
Metoda, gdy używana zthreading
lubmultiprocessing
nie jest związanestr.join()
- to nie jest faktycznie złączenie wszystko razem. Oznacza raczej po prostu „poczekaj na zakończenie tego [wątku / procesu]”. Nazwajoin
jest używana, ponieważmultiprocessing
interfejs API modułu ma wyglądać podobnie dothreading
interfejsu API modułu, athreading
moduł używajoin
dla swojegoThread
obiektu. Używając terminujoin
oznaczającego „czekanie na zakończenie wątku” jest powszechne w wielu językach programowania, więc Python również go przyjął.Powodem, dla którego widzisz 20-sekundowe opóźnienie zarówno z wywołaniem, jak i bez niego,
join()
jest to, że domyślnie, gdy proces główny jest gotowy do zakończenia, niejawnie wywołajoin()
wszystkie uruchomionemultiprocessing.Process
instancje. W dokumentach nie jest to tak jasno określone,multiprocessing
jak powinno, ale zostało to wspomniane w sekcji Wskazówki dotyczące programowania :Możesz zmienić to zachowanie, ustawiając
daemon
flagę naProcess
toTrue
przed rozpoczęciem procesu:Jeśli to zrobisz, proces potomny zostanie zakończony, gdy tylko zakończy się proces główny :
źródło
p.daemon=True
chodziło o „rozpoczęcie procesu w tle, który działa bez blokowania wyjścia programu głównego”. Ale jeśli „Proces demona kończy się automatycznie przed zakończeniem programu głównego”, to do czego dokładnie służy?daemonic
procesu potomnego nie jest zbyt bezpieczne, ponieważ proces zostanie zakończony bez umożliwienia wyczyszczenia wszelkich otwartych zasobów, które może posiadać ... (cd.).multiprocessing
interfejs API został zaprojektowany tak, abythreading
jak najdokładniej naśladować interfejs API.threading.Thread
Obiekty demoniczne są przerywane, gdy tylko główny wątek kończy działanie, więcmultiprocesing.Process
obiekty demoniczne zachowują się w ten sam sposób.Bez tego
join()
główny proces może zakończyć się przed procesem potomnym. Nie jestem pewien, w jakich okolicznościach prowadzi to do zombieizmu.Głównym celem
join()
jest zapewnienie, że proces podrzędny został zakończony, zanim proces główny zrobi cokolwiek, co zależy od pracy procesu podrzędnego.Etymologia
join()
jest taka, że jest przeciwieństwemfork
, co jest powszechnym terminem w systemach operacyjnych z rodziny Unix do tworzenia procesów potomnych. Pojedynczy proces „dzieli się” na kilka, a następnie „łączy” z powrotem w jeden.źródło
join()
ponieważjoin()
jest to, co było używane do oczekiwania nathreading.Thread
ukończenie obiektu, amultiprocessing
API ma naśladowaćthreading
API w jak największym stopniu.join()
jest potrzebny w przypadku, gdy główny wątek potrzebuje wyników pracy pod-wątków. Na przykład, jeśli renderujesz coś i przypisujesz 1/4 końcowego obrazu do każdego z 4 podprocesów, a po zakończeniu chcesz wyświetlić cały obraz.Nie zamierzam szczegółowo wyjaśniać, co to
join
robi, ale oto etymologia i intuicja, która za tym stoi, co powinno pomóc ci łatwiej zapamiętać jego znaczenie.Chodzi o to, że wykonanie „ rozwidla ” wiele procesów, z których jeden jest panem, a pozostali pracownicy (lub „niewolnicy”). Kiedy robotnicy skończą, „dołączają” do kapitana, aby można było wznowić seryjną egzekucję.
join
Metoda powoduje, że proces główny czekać na pracownika do niej przyłączyć. Metoda mogłaby być lepiej nazwana „wait”, ponieważ takie właśnie zachowanie powoduje w masterze (i tak nazywa się w POSIX, chociaż wątki POSIX nazywają ją również „join”). Łączenie następuje tylko w wyniku prawidłowej współpracy nici, nie jest to coś, co robi mistrz .Nazwy „fork” i „join” są używane w tym znaczeniu w przetwarzaniu wieloprocesowym od 1963 roku .
źródło
join
mogło poprzedzać jego użycie w odniesieniu do konkatenacji, w przeciwieństwie do odwrotnej sytuacji.join()
służy do oczekiwania na zakończenie procesu roboczego. Należy zadzwonićclose()
lubterminate()
przed użyciemjoin()
.Podobnie jak @Russell wspomniany łączenie jest przeciwieństwem forka (który wywołuje podprocesy).
Aby dołączyć do uruchomienia, musisz uruchomić,
close()
co zapobiegnie przesyłaniu kolejnych zadań do puli i wyjdzie po zakończeniu wszystkich zadań. Alternatywnie bieganieterminate()
zakończy się natychmiastowym zatrzymaniem wszystkich procesów roboczych."the child process will sit idle and not terminate, becoming a zombie you must manually kill"
jest to możliwe, gdy proces główny (nadrzędny) kończy pracę, ale proces potomny nadal działa, a po zakończeniu nie ma procesu nadrzędnego, do którego mógłby zwrócić swój kod zakończenia.źródło
Te
join()
, zapewnia połączenia że kolejne linie kodu nie są wywoływane przed wieloprocesorowe wszystkie procesy są zakończone.Na przykład bez tego
join()
poniższy kod zostanie wywołanyrestart_program()
jeszcze przed zakończeniem procesów, co jest podobne do asynchronicznego i nie jest tym, czego chcemy (możesz spróbować):źródło
Aby poczekać, aż proces zakończy swoją pracę i zakończy działanie, użyj metody join ().
i
Uwaga Ważne jest, aby dołączyć () do procesu po jego zakończeniu, aby dać maszynom działającym w tle czas na zaktualizowanie stanu obiektu w celu odzwierciedlenia zakończenia.
To dobry przykład pomógł mi to zrozumieć: tutaj
Osobiście zauważyłem, że mój główny proces został wstrzymany, dopóki dziecko nie zakończyło swojego procesu przy użyciu metody join (), która pokonała cel, w jakim używałem
multiprocessing.Process()
w pierwszej kolejności.źródło