W tym artykule omówiono podstawy wielowątkowości w języku programowania Python. Tak jak wieloprocesorowość , wielowątkowość to sposób na osiągnięcie wielozadaniowości. W wielowątkowości koncepcja wątki Jest używane. Najpierw zrozumiemy pojęcie nitka w architekturze komputerów.
Co to jest proces w Pythonie?
W informatyce A proces jest instancją programu komputerowego, który jest wykonywany. Każdy proces składa się z 3 podstawowych elementów:
- Program wykonywalny.
- Powiązane dane potrzebne programowi (zmienne, obszar roboczy, bufory itp.)
- Kontekst wykonania programu (stan procesu)
Wprowadzenie do wątków w Pythonie
A nitka jest elementem procesu, który można zaplanować do wykonania. Jest to także najmniejsza jednostka przetwarzania, jaką można wykonać w systemie operacyjnym. Krótko mówiąc, wątek to sekwencja takich instrukcji w programie, która może zostać wykonana niezależnie od innego kodu. Dla uproszczenia można założyć, że wątek jest po prostu podzbiorem procesu! Wątek zawiera wszystkie te informacje w pliku Blok kontrolny wątku (TCB) :
- Identyfikator wątku: Do każdego nowego wątku przypisywany jest unikalny identyfikator (TID).
- Wskaźnik stosu: Wskazuje stos wątku w procesie. Stos zawiera zmienne lokalne w zakresie wątku.
- Licznik programu: rejestr przechowujący adres instrukcji aktualnie wykonywanej przez wątek.
- Stan wątku: może być uruchomiony, gotowy, czekać, uruchamiany lub gotowy.
- Zestaw rejestrów wątku: rejestry przypisane do wątku do obliczeń.
- Wskaźnik procesu nadrzędnego: Wskaźnik do bloku sterowania procesem (PCB) procesu, w którym działa wątek.
Rozważ poniższy diagram, aby zrozumieć związek pomiędzy procesem a jego wątkiem:

Związek między procesem a jego wątkiem
kiedy wynaleziono szkołę
W jednym procesie może istnieć wiele wątków, gdzie:
- Każdy wątek zawiera swój własny zestaw rejestracyjny I zmienne lokalne (przechowywane na stosie) .
- Wszystkie wątki procesu są współdzielone zmienne globalne (przechowywane na stercie) i kod programu .
Rozważ poniższy diagram, aby zrozumieć, w jaki sposób w pamięci istnieje wiele wątków:

Istnienie wielu wątków w pamięci
Wprowadzenie do wątków w Pythonie
Wielowątkowość definiuje się jako zdolność procesora do jednoczesnego wykonywania wielu wątków. W prostym, jednordzeniowym procesorze osiąga się to poprzez częste przełączanie pomiędzy wątkami. Nazywa się to przełączanie kontekstu . Podczas przełączania kontekstu stan wątku jest zapisywany, a stan innego wątku jest ładowany za każdym razem, gdy ma miejsce jakiekolwiek przerwanie (z powodu wejścia/wyjścia lub ustawienia ręcznego). Przełączanie kontekstu odbywa się tak często, że wydaje się, że wszystkie wątki działają równolegle (jest to tzw wielozadaniowość ).
Rozważmy poniższy diagram, na którym proces zawiera dwa aktywne wątki:

Wielowątkowość
Wielowątkowość w Pythonie
W Pyton , gwintowanie moduł zapewnia bardzo proste i intuicyjne API do tworzenia wielu wątków w programie. Spróbujmy krok po kroku zrozumieć kod wielowątkowy.
Krok 1: Moduł importu
Najpierw zaimportuj moduł wątków.
import threading>
Krok 2: Utwórz wątek
Aby utworzyć nowy wątek, tworzymy obiekt typu Nitka klasa. Jako parametry przyjmuje „cel” i „args”. The cel jest funkcją, która ma zostać wykonana przez wątek, podczas gdy argumenty są argumenty, które mają zostać przekazane do funkcji docelowej.
zmień nazwę w katalogu Linux
t1 = threading.Thread(target, args) t2 = threading.Thread(target, args)>
Krok 3: Rozpocznij wątek
Aby rozpocząć wątek, używamy początek() metoda klasy Thread.
t1.start() t2.start()>
Krok 4: Zakończ wykonanie wątku
Po uruchomieniu wątków bieżący program (można o nim myśleć jak o wątku głównym) również kontynuuje wykonywanie. Aby zatrzymać wykonywanie bieżącego programu do czasu zakończenia wątku, używamy metody dołączyć() metoda.
t1.join() t2.join()>
W rezultacie bieżący program będzie najpierw czekał na zakończenie t1 i wtedy t2 . Po ich zakończeniu wykonywane są pozostałe instrukcje bieżącego programu.
Przykład:
Rozważmy prosty przykład użycia modułu wątków.
Ten kod demonstruje, jak używać modułu wątków Pythona do jednoczesnego obliczania kwadratu i sześcianu liczby. Dwa wątki, t1> I t2> , są tworzone w celu wykonywania tych obliczeń. Są one uruchamiane, a ich wyniki są drukowane równolegle, zanim program wydrukuje Gotowe! gdy oba wątki się zakończą. Wątkowanie służy do osiągnięcia równoległości i poprawy wydajności programu podczas wykonywania zadań wymagających dużej mocy obliczeniowej.
Python3
import> threading> def> print_cube(num):> >print>(>'Cube: {}'> .>format>(num>*> num>*> num))> def> print_square(num):> >print>(>'Square: {}'> .>format>(num>*> num))> if> __name__>=>=>'__main__'>:> >t1>=> threading.Thread(target>=>print_square, args>=>(>10>,))> >t2>=> threading.Thread(target>=>print_cube, args>=>(>10>,))> >t1.start()> >t2.start()> >t1.join()> >t2.join()> >print>(>'Done!'>)> |
>
>
Wyjście:
Square: 100 Cube: 1000 Done!>
Rozważ poniższy diagram, aby lepiej zrozumieć działanie powyższego programu:

Wielowątkowość
Przykład:
W tym przykładzie używamy os.getpid() funkcja, aby uzyskać identyfikator bieżącego procesu. Używamy wątek.main_thread() funkcja, aby uzyskać główny obiekt wątku. W normalnych warunkach wątkiem głównym jest wątek, z którego został uruchomiony interpreter Pythona. nazwa atrybut obiektu wątku służy do uzyskania nazwy wątku. Następnie używamy Threading.current_thread() funkcja, aby uzyskać bieżący obiekt wątku.
Rozważmy program w Pythonie podany poniżej, w którym wypisujemy nazwę wątku i odpowiadający mu proces dla każdego zadania.
przykład mapy Java
Ten kod demonstruje, jak używać modułu wątków Pythona do jednoczesnego wykonywania dwóch zadań. Program główny inicjuje dwa wątki, t1> I t2> , z których każdy jest odpowiedzialny za wykonanie określonego zadania. Wątki działają równolegle, a kod zawiera informacje o identyfikatorze procesu i nazwach wątków. Theos>moduł służy do uzyskiwania dostępu do identyfikatora procesu, a ' threading'> moduł służy do zarządzania wątkami i ich wykonywaniem.
Python3
Konwersja ciągu Java na liczbę całkowitą
import> threading> import> os> def> task1():> >print>(>'Task 1 assigned to thread: {}'>.>format>(threading.current_thread().name))> >print>(>'ID of process running task 1: {}'>.>format>(os.getpid()))> def> task2():> >print>(>'Task 2 assigned to thread: {}'>.>format>(threading.current_thread().name))> >print>(>'ID of process running task 2: {}'>.>format>(os.getpid()))> if> __name__>=>=> '__main__'>:> >print>(>'ID of process running main program: {}'>.>format>(os.getpid()))> >print>(>'Main thread name: {}'>.>format>(threading.current_thread().name))> >t1>=> threading.Thread(target>=>task1, name>=>'t1'>)> >t2>=> threading.Thread(target>=>task2, name>=>'t2'>)> >t1.start()> >t2.start()> >t1.join()> >t2.join()> |
>
>
Wyjście:
ID of process running main program: 1141 Main thread name: MainThread Task 1 assigned to thread: t1 ID of process running task 1: 1141 Task 2 assigned to thread: t2 ID of process running task 2: 1141>
Poniższy diagram wyjaśnia powyższą koncepcję:

Wielowątkowość
To było krótkie wprowadzenie do wielowątkowości w Pythonie. Następny artykuł z tej serii dotyczy synchronizacja pomiędzy wieloma wątkami . Wielowątkowość w Pythonie | Zestaw 2 (synchronizacja)
Pula wątków Pythona
Pula wątków to zbiór wątków tworzonych wcześniej i można ich ponownie używać do wykonywania wielu zadań. Moduł concurrent.futures w Pythonie udostępnia klasę ThreadPoolExecutor, która ułatwia tworzenie puli wątków i zarządzanie nią.
W tym przykładzie definiujemy proces roboczy funkcji, który będzie uruchamiany w wątku. Tworzymy ThreadPoolExecutor z maksymalnie 2 wątkami roboczymi. Następnie przesyłamy dwa zadania do puli za pomocą metody przesyłania. Pula zarządza wykonywaniem zadań w swoich wątkach roboczych. Używamy metody zamykania, aby poczekać na zakończenie wszystkich zadań, zanim główny wątek będzie kontynuowany.
Wielowątkowość może pomóc w zwiększeniu wydajności i responsywności programów. Jednak ważne jest, aby zachować ostrożność podczas pracy z wątkami, aby uniknąć problemów, takich jak warunki wyścigowe i zakleszczenia.
Ten kod wykorzystuje pulę wątków utworzoną za pomocą concurrent.futures.ThreadPoolExecutor> do jednoczesnego wykonywania dwóch zadań roboczych. Główny wątek czeka, aż wątki robocze zakończą pracę pool.shutdown(wait=True)> . Pozwala to na wydajne równoległe przetwarzanie zadań w środowisku wielowątkowym.
Python3
postać normalna Greibacha
import> concurrent.futures> def> worker():> >print>(>'Worker thread running'>)> pool>=> concurrent.futures.ThreadPoolExecutor(max_workers>=>2>)> pool.submit(worker)> pool.submit(worker)> pool.shutdown(wait>=>True>)> print>(>'Main thread continuing to run'>)> |
>
>Wyjście
Worker thread running Worker thread running Main thread continuing to run>