Kiedy powinniśmy wywołać metodę multiprocessing.Pool.join?

96

Używam „multiprocess.Pool.imap_unordered” w następujący sposób

from multiprocessing import Pool
pool = Pool()
for mapped_result in pool.imap_unordered(mapping_func, args_iter):
    do some additional processing on mapped_result

Czy muszę dzwonić, pool.closeczy pool.joinpo pętli for?

hch
źródło
Zwykle dzwonię pool.join()wtedy pool.close()po uruchomieniu wszystkich wątków puli, ale nie próbowałem używać go pool.imap_unordered()jako iterowalnego.
Bamcclur,
8
jaki jest sens wywoływania dołączenia lub zamknięcia? Nie zadzwoniłem do nich i wydaje mi się, że mój kod działa poprawnie. Obawiam się jednak, że nie wywołanie ich spowodowałoby procesy zombie lub inne subtelne rzeczy.
hch

Odpowiedzi:

113

Nie, nie możesz, ale to prawdopodobnie dobry pomysł, jeśli nie zamierzasz już korzystać z basenu.

Powody, dla których warto dzwonić pool.closelub pool.joinsą dobrze opisane przez Tima Petersa w tym poście SO :

Jeśli chodzi o Pool.close (), powinieneś wywołać to wtedy, gdy - i tylko wtedy - nigdy nie będziesz przesyłać więcej pracy do instancji Pool. Tak więc Pool.close () jest zwykle wywoływana po zakończeniu pracującej równolegle części programu głównego. Wówczas procesy robocze zostaną zakończone, gdy wszystkie już przypisane prace zostaną zakończone.

Doskonałą praktyką jest również wywołanie metody Pool.join () w celu oczekiwania na zakończenie procesu roboczego. Między innymi często nie ma dobrego sposobu zgłaszania wyjątków w kodzie równoległym (wyjątki występują w kontekście tylko niejasno związanym z tym, co robi twój główny program), a Pool.join () udostępnia punkt synchronizacji, który może zgłosić niektóre wyjątki, które wystąpiły w procesach roboczych, których inaczej nigdy byś nie zobaczył.

Bamcclur
źródło
9
czy lepiej nazywać jednego przed drugim?
RSHAP
9
Wygląda na to, że ludzie lubią dzwonić jako pool.close()pierwszy i pool.join()drugi. Pozwala to na dodawanie pracy między pool.close()i pool.join(), która nie musi czekać na zakończenie wykonywania puli.
Bamcclur
34
Wystarczy dodać do komentarza @ Bamcclur - nie jest to dobry pomysł, aby pool.close()najpierw zadzwonić , w rzeczywistości jest to obowiązkowe. Z dokumentacji : należy zadzwonić close()lub terminate()przed użyciem join().
Bogd
4
@Bogd Ale dlaczego jest to obowiązkowe? Czy mógłbyś odpowiedzieć na to pytanie?
agdhruv
Odpowiedź na pytanie agdhruva byłaby niesamowita!
Whip
44

Miałem ten sam problem pamięci jako Memory użytkowania stale rosnąć z multiprocessing.pool Pythona , kiedy nie używać pool.close(), a pool.join()podczas korzystania pool.map()z funkcji, która oblicza Odległość Levenshteina. Funkcja działała dobrze, ale nie była poprawnie zbierana na komputerze z systemem Win7 64, a zużycie pamięci wymykało się spod kontroli za każdym razem, gdy funkcja była wywoływana, aż do wyłączenia całego systemu operacyjnego. Oto kod, który naprawił wyciek:

stringList = []
for possible_string in stringArray:
    stringList.append((searchString,possible_string))

pool = Pool(5)
results = pool.map(myLevenshteinFunction, stringList)
pool.close()
pool.join()

Po zamknięciu i wejściu do puli wyciek pamięci zniknął.

Odyseusz Itaka
źródło
1
Otrzymałem, ERROR: Terminated with signal 15zanim dodałem kod czyszczenia, pool.close();pool.join();ale po dodaniu tego kodu czyszczenia nie otrzymuję komunikatów konsoli. więc podejrzewam, przynajmniej w mojej wersji, Python 2.7 z C7, że pula może w jakiś sposób nie sprzątała dokładnie.
Trevor Boyd Smith