2017-09-27 15 views
5

Zgodnie z https://github.com/joblib/joblib/issues/180 i Is there a safe way to create a subprocess from a thread in python? moduł przetwarzania wieloprocesorowego Python nie zezwala na użycie z wewnątrz wątków. Czy to prawda?Bezpieczne wywołanie multiprocessingu z wątku w Pythonie?

Rozumiem, że od grzywny do widelca z wątków, tak długo, jak nie utrzymujesz wątku.Zablokuj, gdy to zrobisz (w bieżącym wątku? W dowolnym miejscu procesu?). Jednak documentation w Pythonie milczy na temat tego, czy wątkowanie. Obiekty blokujące są bezpiecznie udostępniane po rozwidleniu.

Istnieje również: blokady udostępnione z modułu rejestrowania powoduje problemy z fork. https://bugs.python.org/issue6721

Nie jestem pewien, jak powstaje ten problem. Wygląda na to, że stan wszystkich blokad w procesie jest kopiowany do procesu potomnego, gdy bieżący wątek jest rozwidlony (co wydaje się błędem projektowym i pewnym zakleszczeniem). Jeśli tak, to czy używanie przetwarzania wieloprocesowego naprawdę zapewnia jakąkolwiek ochronę przed tym (ponieważ jestem wolny, aby utworzyć mój proces wieloprocesorowy. Po zakończeniu wątkowania. Blokowanie jest tworzone i wprowadzane przez inne wątki, a po wątkach zaczęło się to przy użyciu rejestrowania niezalogowanego. moduł) - dokumentacja modułu wieloprocesorowego również nie mówi o tym, czy multiprocessing.Pools powinny być przydzielane przed blokadami.

Czy zastępuje gwintowanie.Zablokuj wieloprocesorowo. Blokuj wszędzie, unikaj tego problemu i pozwól nam bezpiecznie łączyć wątki i widelce?

+0

W tym wydaniu "sposobu kontrolowania podtytułu, jeśli dołączam inny wątek", moja opinia brzmi: ** nie ma mowy **. powinniśmy preferować wieloprocesowość. Blokować wszędzie? NIE, jeśli proces odbywa się w nieskończonej pętli! – dsgdfg

Odpowiedz

4

Brzmi jak państwo jakichkolwiek blokad w procesie są kopiowane do procesu potomnego gdy prąd widelce wątek (który wydaje się błędem projektu i pewna do impasu).

Nie jest to błąd projektowy, a raczej fork() poprzedzający wielowątkowość jednoprocesową. Stan wszystkich zamków jest kopiowany do procesu potomnego, ponieważ są po prostu obiektami w pamięci; cała przestrzeń adresowa procesu jest kopiowana tak jak w fork. Są tylko złe alternatywy: albo skopiuj wszystkie wątki na widełki, albo odmów rozwidlenie w aplikacji wielowątkowej.

W związku z tym, fork() w wielowątkowość programu nigdy nie było bezpieczne, o ile nie następuje po execve() lub w procesie potomnym.

Czy zastępuje gwintowanie.Zablokuj wieloprocesorowo. Blokuj wszędzie, unikaj tego problemu i pozwól nam bezpiecznie łączyć wątki i widelce?

nr Nic nie sprawia, że ​​jest bezpieczny łączyć wątki i widelce, nie można zrobić.


Problem polega na tym, że gdy masz wiele wątków w procesie, po wywołaniu systemowym fork() nie można bezpiecznie kontynuować uruchamiania programu w systemach POSIX.

Na przykład, Linux podręczniki fork(2):

  • Po fork(2) w wielowątkowym programem, dziecko może bezpiecznie wywołać tylko asynchroniczny sygnał bezpieczne funkcje (patrz signal(7)) aż do czasu, kiedy to nazywa się execve(2).

tj. jest w porządku do fork() w programie wielowątkowym, a następnie wywoływać tylko funkcje asynchroniczne z sygnałami (co jest raczej ograniczonym podzbiorem funkcji C), dopóki proces potomny nie zostanie zastąpiony innym plikiem wykonywalnym!

funkcja

niebezpieczne C wymaga w procesie dzieci są wówczas przykładowo

  • malloc alokacji pamięci dynamicznej
  • żadnych <stdio.h> funkcje wejściowych sformatowanych
  • większość pthread_* funkcje wymagane do obsługi stanu wątku, w tym tworzenie nowych wątków ...

Tak więc jest bardzo mało tego, co dziecko proces może faktycznie bezpiecznie zrobić. Niestety twórcy rdzeni CPython bagatelizują problemy spowodowane przez to. Nawet teraz documentation mówi:

Zauważ, że bezpiecznie rozwidlone wielowątkowe proces jest problematyczne.

Całkiem eufemizm za "niemożliwe".


Jest bezpieczny w użyciu wieloprocesorowe z proces Pythona, który ma wiele wątków kontroli pod warunkiem, że jesteś nie stosując metodę fork startu; w Pythonie 3.4+ jest to now possible to change the start method. W poprzednich wersjach Pythona, w tym w całym Pythonie 2, systemy POSIX zawsze zachowywały się tak, jakby jako metoda początkowa była określona fork; spowodowałoby to niezdefiniowane zachowanie.

Problemy nie są ograniczone tylko do obiektów threading.Lock ale wszystkich blokadę utrzymywaną przez biblioteki standardowej C, C itd. Rozszerzenia Co gorsza, że ​​większość czasu ludzie powiedzieliby „działa na mi”. ... dopóki nie przestanie działać.

Były nawet przypadki, w których pozornie jednostronny program w języku Python jest wielowątkowy w systemie MacOS X, powodując awarie i zakleszczenia podczas korzystania z wieloprocesowości.

Innym problemem jest to, że wszystkie otwarte uchwyty plików, ich użycie, współdzielone gniazda mogą zachowywać się dziwnie w programach z rozwidleniami, ale tak by było nawet w programach jednowątkowych.

TL; DR: using multiprocessing w programach wielowątkowych, z rozszerzeniami C, z otwartych gniazd itp:

  • porządku w 3.4+ & POSIX jeśli jawnie określić metodę wyjścia, które nie jest fork,
  • dobrze w Windowsie, ponieważ nie obsługuje rozwidlania;
  • w Pythonie 2 - 3.3 na POSIX: w większości będziesz strzelał sobie w stopę.
+0

Czy proces wieloprocesowy wewnętrznie wywołuje fork? (W takim przypadku powinniśmy się martwić, jeśli już stworzyliśmy zamek). – user48956

+0

@ user48956 nie ma to nic wspólnego z Python Locks; Rzecz w tym, że nie możesz, naprawdę w żaden sposób, zapobiec złemu zachowaniu z kodu Pythona, jeśli masz program wielowątkowy. –

+0

Nie jestem pewien, czy można powiedzieć, że nie można być bezpiecznym. Myślę, że problem polega na tym, że rozwidlanie odbywa się nieświadomie zamków. W lepszej strukturze (wyższego poziomu) można na przykład potwierdzać lub blokować przy użyciu widelca, dopóki nie będzie aktywnych blokad. Wymagałoby to, że Python zależy tylko od bibliotek C, które są bezpieczne dla widżetów i nie mają blokad, lub że Python gwarantuje, że kod C nie jest wykonywany w trybie fork. Jest to możliwe, ale trudne. Python może zapytać system operacyjny - czy proces ten posiada teraz blokady systemu operacyjnego? jeśli tak, musisz poczekać na rozwidlenie (lub potwierdzić). – user48956

Powiązane problemy