Próbowałem pojąć, jak działają wątki w Pythonie i ciężko jest znaleźć dobre informacje na temat ich działania. Może po prostu brakuje mi linku lub czegoś takiego, ale wygląda na to, że oficjalna dokumentacja nie jest zbyt dokładna w tym temacie i nie udało mi się znaleźć dobrego artykułu.
Z tego, co wiem, na raz może działać tylko jeden wątek, a aktywny wątek przełącza się co około 10 instrukcji?
Gdzie jest dobre wyjaśnienie lub czy możesz je podać? Byłoby również bardzo miło być świadomym typowych problemów, które napotykasz podczas używania wątków w Pythonie.
Python jest dość łatwym językiem do wkręcenia, ale są pewne zastrzeżenia. Największą rzeczą, o której musisz wiedzieć, jest Global Interpreter Lock. Pozwala to tylko jednemu wątkowi na dostęp do interpretera. Oznacza to dwie rzeczy: 1) rzadko zdarza się, że używasz instrukcji lock w Pythonie i 2) jeśli chcesz skorzystać z systemów wieloprocesorowych, musisz użyć oddzielnych procesów. EDYCJA: Powinienem również zaznaczyć, że możesz umieścić część kodu w C / C ++, jeśli chcesz również ominąć GIL.
Dlatego musisz ponownie rozważyć, dlaczego chcesz używać wątków. Jeśli chcesz zrównoleglać swoją aplikację, aby wykorzystać architekturę dwurdzeniową, musisz rozważyć podzielenie aplikacji na wiele procesów.
Jeśli chcesz poprawić responsywność, powinieneś ROZWAŻYĆ użycie wątków. Istnieją jednak inne alternatywy, a mianowicie mikrowłókno . Jest też kilka frameworków, którym powinieneś się przyjrzeć:
źródło
Poniżej znajduje się podstawowa próbka gwintowania. Spowoduje 20 wątków; każdy wątek wyświetli swój numer wątku. Uruchom go i obserwuj kolejność drukowania.
import threading class Foo (threading.Thread): def __init__(self,x): self.__x = x threading.Thread.__init__(self) def run (self): print str(self.__x) for x in xrange(20): Foo(x).start()
Jak już zasugerowałeś, wątki Pythona są implementowane poprzez dzielenie czasu. W ten sposób uzyskują efekt „równoległości”.
W moim przykładzie moja klasa Foo rozszerza wątek, a następnie implementuję
run
metodę, do której trafia kod, który chcesz uruchomić w wątku. Aby uruchomić wątek, który wywołujeszstart()
na obiekcie wątku, który automatycznie wywołarun
metodę ...Oczywiście to tylko podstawy. W końcu będziesz chciał dowiedzieć się o semaforach, muteksach i blokadach do synchronizacji wątków i przekazywania wiadomości.
źródło
Użyj wątków w języku Python, jeśli poszczególni pracownicy wykonują operacje powiązane we / wy. Jeśli próbujesz skalować na wielu rdzeniach na komputerze, znajdź dobrą strukturę IPC dla Pythona lub wybierz inny język.
źródło
Uwaga: wszędzie tam, gdzie wspominam,
thread
mam na myśli wątki w Pythonie, dopóki nie zostanie to wyraźnie określone.Wątki działają trochę inaczej w Pythonie, jeśli przechodzisz z
C/C++
tła. W Pythonie tylko jeden wątek może być uruchomiony w danym momencie, co oznacza, że wątki w Pythonie nie mogą w pełni wykorzystać mocy wielu rdzeni przetwarzających, ponieważ z założenia nie jest możliwe, aby wątki działały równolegle na wielu rdzeniach.Ponieważ zarządzanie pamięcią w Pythonie nie jest bezpieczne dla wątków, każdy wątek wymaga wyłącznego dostępu do struktur danych w interpreterze Pythona, który jest uzyskiwany przez mechanizm o nazwie (globalna blokada interpretr) .
GIL
Why does python use GIL?
Aby zapobiec jednoczesnemu dostępowi wielu wątków do stanu interpretera i uszkodzeniu stanu interpretera.
Chodzi o to, że za każdym razem, gdy wątek jest wykonywany (nawet jeśli jest to główny wątek) , uzyskiwany jest GIL i po pewnym predefiniowanym przedziale czasu GIL jest zwalniany przez bieżący wątek i ponownie pobierany przez inny wątek (jeśli istnieje).
Why not simply remove GIL?
Nie jest tak, że niemożliwe jest usunięcie GIL-a, po prostu w trakcie wykonywania tego w końcu umieszczamy wiele blokad wewnątrz interpretera w celu serializacji dostępu, co sprawia, że nawet pojedyncza aplikacja wątkowa jest mniej wydajna.
więc koszt usunięcia GIL jest opłacany przez zmniejszoną wydajność aplikacji jednowątkowej, co nigdy nie jest pożądane.
So when does thread switching occurs in python?
Zmiana wątku następuje po wydaniu GIL. Więc kiedy GIL zostanie wydany? Należy wziąć pod uwagę dwa scenariusze.
Jeśli wątek wykonuje operacje związane z procesorem (przetwarzanie obrazu Ex).
W starszych wersjach Pythona przełączanie wątków występowało po ustalonej liczbie instrukcji Pythona, domyślnie było ustawione na
100
. Okazało się, że nie jest to zbyt dobra polityka decydowania o przełączeniu, ponieważ czas spędzony na wykonywaniu pojedynczej instrukcji może bardzo szalenie od milisekundy do nawet sekundy, dlatego zwalnianie GIL po każdej100
instrukcji, niezależnie od czasu jej wykonania, jest złą polityką.W nowych wersjach zamiast używania liczby instrukcji jako metryki przełączania wątku, używany jest konfigurowalny przedział czasu. Domyślny interwał przełączania to 5 milisekund. Bieżący interwał przełączania można uzyskać za pomocą
sys.getswitchinterval()
. Można to zmienić za pomocąsys.setswitchinterval()
Jeśli wątek wykonuje operacje związane z operacjami we / wy (dostęp do systemu plików Ex lub we /
wy sieci)
GIL jest wydawany, gdy wątek czeka na zakończenie operacji we / wy.
Which thread to switch to next?
Interpreter nie ma własnego harmonogramu, a który wątek zostanie zaplanowany na koniec interwału, jest decyzją systemu operacyjnego. .
źródło
Jednym prostym rozwiązaniem GIL jest moduł wieloprocesowy . Może być używany jako kropla w zastępstwie modułu wątkowego, ale używa wielu procesów interpretera zamiast wątków. Z tego powodu w przypadku prostych rzeczy jest trochę więcej narzutów niż zwykłe gwintowanie, ale daje to korzyść prawdziwej równoległości, jeśli jej potrzebujesz. Można go również łatwo skalować do wielu fizycznych komputerów.
Jeśli potrzebujesz naprawdę wielkoskalowej równoległości, nie szukałbym dalej, ale jeśli chcesz po prostu skalować do wszystkich rdzeni jednego komputera lub kilku różnych bez całej pracy, która wymagałaby wdrożenia bardziej kompleksowej struktury, to jest to dla ciebie .
źródło
Spróbuj zapamiętać, że GIL jest ustawiony tak często, aby sondować wokół, aby pokazać wygląd wielu zadań. To ustawienie można precyzyjnie dostroić, ale sugeruję, że powinno być trochę pracy, którą wykonują wątki lub wiele przełączników kontekstu spowoduje problemy.
Posunąłbym się do tego, że zasugerowałbym wielu rodziców na procesorach i starałbym się utrzymać podobne zadania na tych samych rdzeniach.
źródło