23 februarie 2011

Fire de executie in Python

Un exemplu de program in Python care afiseaza (oarecum aleator) id-urile unor thread-uri aflate in executie:

import time
from threading import Thread
from threading import Lock

class MyThread(Thread):

def __init__(self,n):
Thread.__init__(self)
self.tid=n

def run(self):
a = 0
for i in range(100000):
a += 1
print self.tid
def test():
nt = 10
for i in range(nt):
thr1=MyThread(i)
thr1.start()
thr1.join()

test()


Elementele de sincronizare in Python sunt:

* Lock - se poate afla intr-una din doua stari:

- blocat: daca se apeleaza release() se trece in starea neblocat

  • - neblocat (este creat neblocat): daca se apeleaza acquire() se trece in starea blocat

    Exemplu: Acelasi program de mai sus, insa cu id-urile threadurilor afisate ordonat (se foloseste Lock pentru ca in momentul afisarii zona sa fie exclusiv a firului de executie si sa nu poata interfera un alt thread)
import time
from threading import Thread
from threading import Lock

# afisare in ordine folosind lock
class MyThread(Thread):

def __init__(self,n):
Thread.__init__(self)
self.tid=n

def run(self):
a = 0
lock.acquire()
for i in range(100000):
a += 1
print self.tid
lock.release()
def test():
nt = 10
for i in range(nt):
thr1=MyThread(i)
thr1.start()
thr1.join()

lock = Lock()
test()


* Mecanisme de comunicatie - evenimente si conditii

Evenimente: un thread semnalizeaza un eveniment - notify(), iar altul asteapta ca evenimentul sa se intample - wait().

In Python, un obiect de tip event are un flag intern, initial setat pe false. Acesta poate fi setat pe true cu functia set() si resetat folosind clear(). Pentru a verifica starea flag-ului, se apeleaza functia isSet().

Un alt thread poate folosi metoda wait([timeout]) pentru a astepta ca un eveniment sa se intample (ca flag-ul sa devina true): daca in momentul apelarii wait(), flag-ul este true, thread-ul apelant nu se blocheaza, dar daca este false se blocheaza pana la setarea eventului. De altfel, la un set(), toate thread-urile care asteptau event-ul cu wait() vor fi notificate (si eligibile deci pentru a rula).

O variabila de tip conditie (Condition) este asociata cu un obiect mutex Lock. Acesta poate fi transmis ca parametru atunci cand mai multe variabile condition partajeaza un lock sau poate fi creat implicit.

Metodele prezente sunt acquire() si release() care le apeleaza pe cele corespunzatoare lock-ului si mai exista functiile wait(), notify() si notifyAll(), apelabile doar daca s-a reusit obtinerea lock-ului:

  • - metoda wait() elibereaza lock-ul si se blocheaza in asteptarea unei notificari
  • - metoda notify() deblocheaza un singur thread aflat in asteptare
  • - metoda notifyAll() deblocheaza toate thread-urile care asteptau indeplinirea conditiei

! Apelurile notify() si notifyAll() nu elibereaza lock-ul, deci un thread nu va fi trezit imediat ci doar cand apeluri de mai sus au terminat de folosit lock-ul si l-au eliberat.


* Semafoarele - sunt obiecte de sincronizare similare Lock-urilor insa difera de acestea prin faptul ca salveaza numarul de operatii de deblocare efectuate asupra lor. Un semafor gestioneaza un contor intern care este decrementat de un apel acquire() si incrementat de apelul release().

Contorul nu poate ajunge la valori negative deci atunci cand este apelata functia acquire() si contorul este 0 thredul se blocheaza pana cand alt thread apeleaza release(). Atunci cand este creat un semafor contorul are valoarea 1.

Exemplu: Problema producator-consumator, cand 3 producatori, 1 consumator si buffer nelimitat.


import time

import random

from threading import Thread

import threading

sem1 = threading.Semaphore(value=3) # 3 prod

# cons nu are semafor


class Prod(Thread):

def __init__(self,buf,n):

Thread.__init__(self)

self.idt = n

self.buf = buf


def run(self):

while True:

global sem1

sem1.acquire()

self.buf.append(1)

print "Prod",self.idt, " produce; Buffer=", self.buf

time.sleep(random.random()*5)

sem1.release()


class Cons(Thread):


def __init__(self,buf,idt):

Thread.__init__(self)

self.idt = idt

self.buf = buf


def run(self):

while True:

if len(self.buf) > 0:

del self.buf[0]

print "Cons",self.idt, " consuma; Buffer=", self.buf

time.sleep(random.random()*5)


def test():

buf = []

p1 = Prod(buf,0)

p2 = Prod(buf,1)

p3 = Prod(buf,2)

c = Cons(buf,0)

p1.start()

p2.start()

p3.start()

c.start()

test()

Niciun comentariu: