Kurs języka Python
Wątki
Wątek
Wątek (ang. thread) to jednostka
wykonawcza w obrębie jednego procesu,
będąca kolejnym ciągiem instrukcji
wykonywanym w obrębie tych samych
danych (w tej samej przestrzeni adresowej).
Wątki tego samego procesu korzystają ze
wspólnego kodu i danych, mają jednak
oddzielne stosy.
yródło: www.wikipedia.pl
Do czego używa się wątków
Serwery (np. WWW), które obsługujące wielu
klientów
Obsługa systemów GUI; zlecenie wykonania
zadania nie powoduje 'zamrożenia' działania
interfejsu
Wątki, przykład
i = i + 1 print i i = i + 1 print i i = i + 1 print i
i = i - 1 print i i = i - 1 print i i = i - 1 print i
MASZYNA
WIRTUALNA
Przykładowy przebieg
i = i + 1 print i i = i + 1 print i i = i + 1 print i
i = i - 1 print i i = i - 1 print i i = i - 1 print i
MASZYNA
WIRTUALNA
Przykładowy przebieg
i = i + 1 print i i = i + 1 print i i = i + 1 print i
i = i - 1 print i i = i - 1 print i i = i - 1 print i
MASZYNA
WIRTUALNA
Moduł threading
class Thread:
def start(self):
'''Wywołuje metodę run'''
def run(self): pass
Zadanie
Zasymulowanie za pomocą wątków biegaczy w
maratonie.
Implementacja biegaczy
import threading
total_distance = 0
class runner(threading.Thread):
def __init__(self, nr_startowy):
self.numer = nr_startowy
threading.Thread.__init__(self)
Implementacja biegu
def run(self):
global total_distance
dystans = 42195
while dystans > 0:
dystans = dystans - 1
total_distance = total_distance + 1
if dystans % 10000 == 0:
print 'Zawodnik nr %i' % self.numer
print 'Zawodnik %i na mecie' % self.numer
Rozpoczęcie wyścigu
r1 = runner(1)
r2 = runner(2)
r1.start()
r2.start()
r1.join()
r2.join()
print 'koniec wyścigu, dystans', total_distance
.join()
'Główny' program to też wątek, to oznacza że
po wywołaniu
r1.start()
są DWA wątki
w.join() powoduje czekanie na zakończenie
wątku w
Dostęp do wspólnej zmiennej
total_distance = 0
class runner(threading.Thread):
...
total_distance = total_distance + 1
print total_distance
Zagadka
Jaka jest wartość zmiennej total_distance?
Operacje 'atomowe'?
i = i + 1
Wątek 1: Wątek 2:
Wątek 1:
LOADFAST 0 LOADFAST 0
LOADFAST 0 LOADFAST 0
LOAD_CONST 1 LOAD_CONST 1
LOAD_CONST 1 LOAD_CONST 1
BINARY_ADD BINARY_ADD
BINARY_ADD BINARY_ADD
STORE_FAST 0 STORE_FAST 0
STORE_FAST 0 STORE_FAST 0
Blokady
Lock
lock = Lock()
def run(self):
global lock
...
lock.acquire()
total_distance = total_distance + 1
lock.release()
Lock
Szybko działa
Możliwość samozakleszczenia:
lock.acquire()
lock.acquire()
Blokady wielowchodliwe
(reentrant)
lock = threading.RLock()
lock.acquire()
...
lock.acquire()
i = i + 1
lock.release()
...
lock.release()
RLock
Aby zwolnienić blokadę trzeba zwolnić ją tyle
razy ile została założona
Program jest wyraznie wolniejszy od programu
z blokadami typu Lock
Modyfikacja zadania
sztafeta
Każdy biegacz ma zmienną 'pałeczka', która
ma wartość 0 lub 1
Jeśli pałeczka == 0, to biegacz musi czekać w
miejscu, aż mu ją ktoś przekaże, tj. ustawi
paleczka == 1
Pierwsze podejście
Posiadacz = 1 # zmienna globalna
# aktywne czekanie, wątek nr. n
while posiadacz != n: pass
Synchronizacja wątków
class Biegacz(threading.Thread):
def __init__(self, nr_startowy, blokada,
nastepny=None, paleczka=0):
self.numer = nr_startowy
self.blokada = blokada
self.paleczka = paleczka
self.nastepny = nastepny
threading.Thread.__init__(self)
def run(self):
dystans = 40000
self.blokada.acquire()
while self.paleczka == 0:
self.blokada.wait()
print "%i wystartowal" % self.numer
while dystans > 0:
dystans = dystans - 1
if self.nastepny:
self.paleczka = 0
self.nastepny.paleczka = 1
self.blokada.notifyAll()
self.blokada.release()
print "zawodnik %i dobiegl" % self.numer
lock = threading.Condition()
r4 = Biegacz(4, lock)
r3 = Biegacz(3, lock, r4)
r2 = Biegacz(2, lock, r3)
r1 = Biegacz(1, lock, r2, 1)
for r in [r4, r3, r2, r1]:
r.start()
Mechanizmy
wake() - zwalnia uzyskaną blokadę i 'zasypia'
dopóki nie zostanie obudzony. Po obudzeniu
otrzymuje blokadę
notify() - 'budzi' inny wątek uśpiony przy tej
blokadzie metodą wake
notifyAll() - budzi wszystkie wątki, które
przysnęły przy tej blokadzie
Komunikacja między wątkami
skrzynka = ''
# nadawca
lock.acquire()
while len(skrzynka) > 0: lock.wait()
skrzynka = 'komunikat'
lock.notify()
lock.release()
Odbiorca
lock.acquire()
while len(skrzynka) == 0: skrzynka.wait()
print skrzynka
skrzynka = ''
lock.notify()
lock.release()
Wady
Nie można zbuforować więcej niż jeden
komunikat
Jeśli dwa wątki pracują z różną wydajnością, to
szybszy będzie ciągle spowalniany
Dostęp do struktur danych
Zwykle struktury danych nie są bezpieczne ze
względu na wątki (thread-safe)
Klasa Queue
Kolejka FIFO przechowująca obiekty
Bezpieczna ze względu na wątki
Metody
Konstruktor: Queue(rozmiar)
put(item)
get(item)
Zastosowanie praktyczne
Testowanie wydajności serwera WWW
zalewając go odwołaniami do strony
Architektura
Scenariusze (lista kolejnych odwołań), np:
[ "/", "/cms/pl/about_institute", "/"]
Równoległe uruchomienie wielu tych samych
scenariuszy
ROZWIZANIE
Implementacja własnej miniprzeglądarki
działającej jako wewnątrz własnego wątka
Implementacja klasy HttpBrowser
Implementacja
class HttpBrowser(threading.Thread):
def __init__(self, connection, host, scenariusz):
def run(self):
host = "www.ii.uni.wroc.pl"
scenariusz = [ "/", "/cms/pl/about_institute", "/"]
agenty = [ HttpBrowser(
httplib.HTTPConnection, host, scenariusz)
for a in range(20) ]
for a in agenty: a.start()
Najbliższa przyszłość
Sieci (protokoły http, SOAP etc.)
Jeszcze o Pythonie (m.in. refleksje)
Współpraca z innymi językami (C, Java, Mono)
Narzędzia developerskie (testowanie,
debuggowanie, profilowanie)
Wyszukiwarka
Podobne podstrony:
python 8Python Od podstawMonty Python I Święty Graal (Monty Python And The Holy Grail) [1975]pythonPython wykladMonty Python Jabberwocky 1977instr khe pythonslowniki w pythoniePYTHON V1instalwięcej podobnych podstron