Implementacja Threads
W tym rozdziale dowiemy się, jak zaimplementować wątki w Pythonie.
Moduł Pythona do implementacji wątków
Wątki Pythona są czasami nazywane lekkimi procesami, ponieważ wątki zajmują znacznie mniej pamięci niż procesy. Wątki pozwalają na wykonywanie wielu zadań jednocześnie. W Pythonie mamy dwa następujące moduły, które implementują wątki w programie -
<_thread>module
<threading>module
Główna różnica między tymi dwoma modułami polega na tym <_thread> moduł traktuje wątek jako funkcję, podczas gdy <threading>moduł traktuje każdy wątek jako obiekt i implementuje go w sposób obiektowy. Ponadto<_thread>jest skuteczny w wątkach niskiego poziomu i ma mniej możliwości niż <threading> moduł.
Moduł <_thread>
We wcześniejszej wersji Pythona mieliśmy rozszerzenie <thread>moduł, ale od dłuższego czasu był uważany za „przestarzały”. Zachęcamy użytkowników do korzystania z<threading>moduł zamiast. Dlatego w Pythonie 3 moduł „wątek” nie jest już dostępny. Nazwa została zmieniona na „<_thread>"dla wstecznej niezgodności w Pythonie3.
Aby wygenerować nowy wątek za pomocą <_thread> musimy wywołać moduł start_new_threadmetoda. Działanie tej metody można zrozumieć za pomocą następującej składni -
_thread.start_new_thread ( function, args[, kwargs] )
Tutaj -
args jest krotką argumentów
kwargs jest opcjonalnym słownikiem argumentów słów kluczowych
Jeśli chcemy wywołać funkcję bez przekazywania argumentu, musimy użyć pustej krotki argumentów w args.
To wywołanie metody zwraca natychmiast, uruchamia się wątek potomny i wywołuje funkcję z przekazaną listą argumentów, jeśli istnieje. Wątek kończy się jako i kiedy funkcja zwraca.
Przykład
Poniżej znajduje się przykład generowania nowego wątku przy użyciu <_thread>moduł. Używamy tutaj metody start_new_thread ().
import _thread
import time
def print_time( threadName, delay):
count = 0
while count < 5:
time.sleep(delay)
count += 1
print ("%s: %s" % ( threadName, time.ctime(time.time()) ))
try:
_thread.start_new_thread( print_time, ("Thread-1", 2, ) )
_thread.start_new_thread( print_time, ("Thread-2", 4, ) )
except:
print ("Error: unable to start thread")
while 1:
pass
Wynik
Poniższe dane wyjściowe pomogą nam zrozumieć generowanie nowych wątków bz pomocą <_thread> moduł.
Thread-1: Mon Apr 23 10:03:33 2018
Thread-2: Mon Apr 23 10:03:35 2018
Thread-1: Mon Apr 23 10:03:35 2018
Thread-1: Mon Apr 23 10:03:37 2018
Thread-2: Mon Apr 23 10:03:39 2018
Thread-1: Mon Apr 23 10:03:39 2018
Thread-1: Mon Apr 23 10:03:41 2018
Thread-2: Mon Apr 23 10:03:43 2018
Thread-2: Mon Apr 23 10:03:47 2018
Thread-2: Mon Apr 23 10:03:51 2018
moduł <threading>
Plik <threading>moduł implementuje się w sposób obiektowy i traktuje każdy wątek jako obiekt. W związku z tym zapewnia znacznie wydajniejszą obsługę wysokiego poziomu dla wątków niż moduł <_thread>. Ten moduł jest zawarty w Pythonie 2.4.
Dodatkowe metody w module <threading>
Plik <threading> moduł zawiera wszystkie metody <_thread>moduł, ale zapewnia również dodatkowe metody. Dodatkowe metody są następujące -
threading.activeCount() - Ta metoda zwraca liczbę aktywnych obiektów wątku
threading.currentThread() - Ta metoda zwraca liczbę obiektów wątku w kontrolce wątku wywołującego.
threading.enumerate() - Ta metoda zwraca listę wszystkich aktualnie aktywnych obiektów wątku.
run() - Metoda run () jest punktem wejścia dla wątku.
start() - Metoda start () uruchamia wątek przez wywołanie metody run.
join([time]) - Join () czeka na zakończenie wątków.
isAlive() - Metoda isAlive () sprawdza, czy wątek nadal jest wykonywany.
getName() - Metoda getName () zwraca nazwę wątku.
setName() - Metoda setName () ustawia nazwę wątku.
Do implementacji wątków <threading> moduł ma Thread klasa, która udostępnia następujące metody -
Jak tworzyć wątki za pomocą modułu <threading>?
W tej sekcji dowiemy się, jak tworzyć wątki przy użyciu <threading>moduł. Wykonaj poniższe czynności, aby utworzyć nowy wątek za pomocą modułu <threading> -
Step 1 - W tym kroku musimy zdefiniować nową podklasę klasy Thread klasa.
Step 2 - Następnie, aby dodać dodatkowe argumenty, musimy zastąpić __init__(self [,args]) metoda.
Step 3 - W tym kroku musimy nadpisać metodę run (self [, args]), aby zaimplementować to, co wątek powinien zrobić po uruchomieniu.
Teraz, po utworzeniu nowego Thread podklasy, możemy utworzyć jej instancję, a następnie rozpocząć nowy wątek, wywołując plik start(), co z kolei wywołuje run() metoda.
Przykład
Rozważ ten przykład, aby dowiedzieć się, jak wygenerować nowy wątek przy użyciu <threading> moduł.
import threading
import time
exitFlag = 0
class myThread (threading.Thread):
def __init__(self, threadID, name, counter):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
def run(self):
print ("Starting " + self.name)
print_time(self.name, self.counter, 5)
print ("Exiting " + self.name)
def print_time(threadName, delay, counter):
while counter:
if exitFlag:
threadName.exit()
time.sleep(delay)
print ("%s: %s" % (threadName, time.ctime(time.time())))
counter -= 1
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print ("Exiting Main Thread")
Starting Thread-1
Starting Thread-2
Wynik
Rozważmy teraz następujący wynik -
Thread-1: Mon Apr 23 10:52:09 2018
Thread-1: Mon Apr 23 10:52:10 2018
Thread-2: Mon Apr 23 10:52:10 2018
Thread-1: Mon Apr 23 10:52:11 2018
Thread-1: Mon Apr 23 10:52:12 2018
Thread-2: Mon Apr 23 10:52:12 2018
Thread-1: Mon Apr 23 10:52:13 2018
Exiting Thread-1
Thread-2: Mon Apr 23 10:52:14 2018
Thread-2: Mon Apr 23 10:52:16 2018
Thread-2: Mon Apr 23 10:52:18 2018
Exiting Thread-2
Exiting Main Thread
Program w Pythonie dla różnych stanów wątków
Istnieje pięć stanów wątku - nowy, możliwy do uruchomienia, uruchomiony, oczekujący i martwy. Spośród tych pięciu Z tych pięciu skupimy się głównie na trzech stanach - biegnących, oczekujących i martwych. Wątek pobiera swoje zasoby w stanie uruchomionym, czeka na zasoby w stanie oczekiwania; ostateczne wydanie zasobu, jeśli wykonywane i nabyte znajduje się w stanie martwym.
Poniższy program w Pythonie za pomocą metod start (), sleep () i join () pokaże, w jaki sposób wątek wszedł odpowiednio w stan uruchomiony, oczekujący i martwy.
Step 1 - Zaimportuj niezbędne moduły, <wątek> i <czas>
import threading
import time
Step 2 - Zdefiniuj funkcję, która zostanie wywołana podczas tworzenia wątku.
def thread_states():
print("Thread entered in running state")
Step 3 - Używamy metody sleep () modułu czasu, aby nasz wątek czekał powiedzmy 2 sekundy.
time.sleep(2)
Step 4 - Teraz tworzymy wątek o nazwie T1, który przyjmuje argument funkcji zdefiniowanej powyżej.
T1 = threading.Thread(target=thread_states)
Step 5- Teraz za pomocą funkcji start () możemy uruchomić nasz wątek. Wyprodukuje komunikat, który został przez nas ustawiony podczas definiowania funkcji.
T1.start()
Thread entered in running state
Step 6 - Teraz możemy wreszcie zabić wątek metodą join () po zakończeniu jej wykonywania.
T1.join()
Uruchamianie wątku w Pythonie
W pythonie możemy rozpocząć nowy wątek na różne sposoby, ale najłatwiejszym z nich jest zdefiniowanie go jako pojedynczej funkcji. Po zdefiniowaniu funkcji możemy przekazać to jako cel dla nowegothreading.Threadobiekt i tak dalej. Wykonaj następujący kod w języku Python, aby zrozumieć, jak działa funkcja -
import threading
import time
import random
def Thread_execution(i):
print("Execution of Thread {} started\n".format(i))
sleepTime = random.randint(1,4)
time.sleep(sleepTime)
print("Execution of Thread {} finished".format(i))
for i in range(4):
thread = threading.Thread(target=Thread_execution, args=(i,))
thread.start()
print("Active Threads:" , threading.enumerate())
Wynik
Execution of Thread 0 started
Active Threads:
[<_MainThread(MainThread, started 6040)>,
<HistorySavingThread(IPythonHistorySavingThread, started 5968)>,
<Thread(Thread-3576, started 3932)>]
Execution of Thread 1 started
Active Threads:
[<_MainThread(MainThread, started 6040)>,
<HistorySavingThread(IPythonHistorySavingThread, started 5968)>,
<Thread(Thread-3576, started 3932)>,
<Thread(Thread-3577, started 3080)>]
Execution of Thread 2 started
Active Threads:
[<_MainThread(MainThread, started 6040)>,
<HistorySavingThread(IPythonHistorySavingThread, started 5968)>,
<Thread(Thread-3576, started 3932)>,
<Thread(Thread-3577, started 3080)>,
<Thread(Thread-3578, started 2268)>]
Execution of Thread 3 started
Active Threads:
[<_MainThread(MainThread, started 6040)>,
<HistorySavingThread(IPythonHistorySavingThread, started 5968)>,
<Thread(Thread-3576, started 3932)>,
<Thread(Thread-3577, started 3080)>,
<Thread(Thread-3578, started 2268)>,
<Thread(Thread-3579, started 4520)>]
Execution of Thread 0 finished
Execution of Thread 1 finished
Execution of Thread 2 finished
Execution of Thread 3 finished
Wątki demona w Pythonie
Przed zaimplementowaniem wątków demonów w Pythonie musimy wiedzieć o wątkach demonów i ich zastosowaniu. Jeśli chodzi o przetwarzanie danych, demon jest procesem w tle, który obsługuje żądania różnych usług, takich jak wysyłanie danych, przesyłanie plików itp. Byłoby uśpione, gdyby nie było już potrzebne. To samo zadanie można wykonać również przy pomocy wątków innych niż demonowe. Jednak w tym przypadku główny wątek musi ręcznie śledzić wątki niebędące demonami. Z drugiej strony, jeśli używamy wątków demonów, główny wątek może całkowicie o tym zapomnieć i zostanie zabity, gdy główny wątek zostanie zamknięty. Inną ważną kwestią dotyczącą wątków demonów jest to, że możemy zdecydować się na używanie ich tylko do nieistotnych zadań, które nie wpłyną na nas, jeśli nie zostaną ukończone lub zostaną zabite w międzyczasie. Poniżej znajduje się implementacja wątków demonów w Pythonie -
import threading
import time
def nondaemonThread():
print("starting my thread")
time.sleep(8)
print("ending my thread")
def daemonThread():
while True:
print("Hello")
time.sleep(2)
if __name__ == '__main__':
nondaemonThread = threading.Thread(target = nondaemonThread)
daemonThread = threading.Thread(target = daemonThread)
daemonThread.setDaemon(True)
daemonThread.start()
nondaemonThread.start()
W powyższym kodzie są dwie funkcje, a mianowicie >nondaemonThread() i >daemonThread(). Pierwsza funkcja drukuje swój stan i przechodzi w stan uśpienia po 8 sekundach, podczas gdy funkcja deamonThread () drukuje Hello co 2 sekundy przez czas nieokreślony. Możemy zrozumieć różnicę między wątkami nondaemon i daemon za pomocą następujących danych wyjściowych -
Hello
starting my thread
Hello
Hello
Hello
Hello
ending my thread
Hello
Hello
Hello
Hello
Hello