Programowanie współbieżne Zadanie 2

Transkrypt

Programowanie współbieżne Zadanie 2
150875
151021
numer indeksu
Grzegorz Graczyk
numer indeksu
Paweł Tarasiuk
imie i nazwisko
Data
Kierunek
Specjalizacja
Rok akademicki
Semestr
imie i nazwisko
2011-11-07
Informatyka
Inżynieria Oprgoramowania i Analiza Danych
2011/12
7
Programowanie współbieżne
Zadanie 2 - Semafory
Wstęp
Zadanie laboratoryjne polegało na stworzeniu programu mnożącego dwie kwadratowe macierze liczb rzeczywistych n × n, wykorzystującego mechanizm semafor. Przygotowany w języku
Python program pozwala regulować limit wątków pracujących jednocześnie, co umożliwiło nam
zbadanie zależności pomiędzy wielkością tego limitu, a czasem wykonania programu.
Rozwiązanie
Rozwiązanie zostało przygotowane w języku Python, z wykorzystaniem biblioteki multiprocessing. Biblioteka ta udostępnia API równoważne wobec biblioteki threading - różnica polega
na tym, że multiprocessing pozwala operować na wątkach w rozumieniu systemu operacyjnego, kosztem mniejszej liczby wspieranych platform (pośród których i tak znajdują się platformy
Windows oraz GNU/Linux). Podczas gdy Pythonowy threading służy jedynie stworzeniu pozorów równoległości, multiprocessing pozwala w realny sposób rozkładać działania pomiędzy
jednostki obliczeniowe, co znajduje odzwierciedlenie w korzystnych czasach wykonania.
Rozwiązanie oparte jest na funkcji map w języku Python, która pozwala zaaplikować funkcję
jednoargumentową dla każdego elementu listy naraz, tzn na podstawie [a1 , . . . , an ] wyznaczyć
[f (a1 ), . . . , f (an )]. W przypadku programowania jednowątkowego, jest to jedynie uproszczenie
składni języka Python. Sytuacja zmienia się diametralnie w przypadku wykorzystania klasy multiprocessing.Pool. Klasa ta pozwala przygotować środowisko do jednoczesnego uruchomienia
wielu wątków - udostępnia także metodę map, która działa tak samo jak funkcja map wbudowana w język Python, lecz obliczenia dla każdego z elementów uruchamia w osobnym wątku.
W proponowanym rozwiązaniu, aby wykorzystanie semafor było klarowne - właśnie za pomocą
klasy multiprocessing.BoundedSemaphore kontrolowana jest liczba wątków wykonujących
obliczenia jednocześnie. Każdy z nich oblicza jeden wiersz iloczynu macierzy. Jednoczesny odczyt wartości elementów mnożonych macierzy przez wiele wątków nie powoduje konfliktów, zaś
za odpowiednie ułożenie wyznaczanych wierszy wyniku odpowiada metoda map.
Poza klasą BoundedSemaphore, w pakiecie multiproecssing istnieje także Semaphore.
Różnica polega na tym, że multiprocessing.BoundedSemaphore nie pozwala nigdy na to,
aby w pewnym momencie liczba wywołań release (inkrementacja s) przekroczyła liczbę wywołań acquire (dekrementacja s) - czyni to tą klasę bardziej podobną do naszych teoretycznych
rozważań na temat semafor.
PSK: Grzegorz Graczyk i Paweł Tarasiuk
2/5
Wyniki
Pomiar czasu został wykonany dla macierzy 250 × 250 wypełnionych liczbami pseudolosowymi z zakresu (−1000, 1000), zapisanymi z dokładnością do dwóch miejsc dziesiętnych.
10
Program wielowątkowy
Program jednowątkowy
9
8
Czas [s]
7
6
5
4
3
2
1
1
2
3
4
5
6
7
8
9 10 11 12 13 14 15 16 17 18 19 20
Liczba jednoczesnych wątków
Kod programu
#! / u s r / b i n / env python2
from s y s import s t d i n , e x i t , argv
from m u l t i p r o c e s s i n g import Lock , BoundedSemaphore , Pool
def read words ( ) :
w = ’’
c = s t d i n . read (1)
while c :
i f c . isspace ():
i f w:
yield w
w = ’’
else :
w += c
c = s t d i n . read (1)
d e f next word ( ) :
f o r w in read words ( ) :
return w
return ’ ’
def valid input ( t ) :
w = next word ( )
try :
r e t u r n t (w)
except :
p r i n t ( ’ I n c o r r e c t i n p u t . Expected data c o n v e r t a b l e t o ’ + s t r ( t ) +
’ , g o t \” ’ + s t r (w) + ’ \ ” . ’ )
exit (1)
PSK: Grzegorz Graczyk i Paweł Tarasiuk
3/5
d e f m a t r i x r e p r (M) :
i f n == 1 :
r e t u r n [ ’ ( ’ + M[ 0 ] [ 0 ] + ’ ) ’ ]
r e s u l t = [ ’ ’ f o r i i n xrange ( n ) ]
l = 0
f o r r i n xrange ( n ) :
f o r c i n xrange ( n ) :
l = max( l , l e n ( s t r (M[ r ] [ c ] ) ) )
f o r r i n xrange ( n ) :
r e s u l t [ r ] += ( ’ / ’ i f r == 0 e l s e ’ \\ ’ i f r == n − 1 e l s e ’ | ’ )
f o r c i n xrange ( n ) :
t = s t r (M[ r ] [ c ] )
r e s u l t [ r ] += ( ’ ’ ∗ ( l + 1 − l e n ( t ) ) ) + t
r e s u l t [ r ] += ’ ’ + ( ’ \\ ’ i f r == 0 e l s e ’ / ’ i f r == n − 1 e l s e
return r e s u l t
def p r i n t c a l c u l a t i o n ( ) :
Ar = m a t r i x r e p r (A)
Br = m a t r i x r e p r (B)
Cr = m a t r i x r e p r (C)
h = n // 2
f o r r in range (n ) :
i f r == h :
p r i n t Ar [ r ] + ’
else :
p r i n t Ar [ r ] + ’
x
’ + Br [ r ] + ’
=
’ + Br [ r ] + ’
’| ’)
’ + Cr [ r ]
’ + Cr [ r ]
def p r i n t r e s u l t ( ) :
f o r r i n xrange ( n ) :
f o r c i n xrange ( n ) :
p r i n t C[ r ] [ c ] ,
print
d l = Lock ( )
d e f debug ( s ) :
dl . acquire ()
print s
dl . r e l e a s e ()
s = BoundedSemaphore ( i n t ( argv [ 1 ] ) )
d e f f i l l c e l l ( pos ) :
s . acquire ()
r = pos // n
c = pos % n
result = 0.0
f o r t in range (n ) :
r e s u l t += A[ r ] [ t ] ∗ B [ t ] [ c ]
s . release ()
return r e s u l t
n = valid input ( int )
A = [ [ 0 . 0 f o r c i n xrange ( n ) ] f o r r i n xrange ( n ) ]
B = [ [ 0 . 0 f o r c i n xrange ( n ) ] f o r r i n xrange ( n ) ]
PSK: Grzegorz Graczyk i Paweł Tarasiuk
4/5
f o r r i n x range ( n ) :
f o r c i n xrange ( n ) :
A[ r ] [ c ] = v a l i d i n p u t ( f l o a t )
f o r r i n x range ( n ) :
f o r c i n xrange ( n ) :
B[ r ] [ c ] = v a l i d i n p u t ( f l o a t )
C = []
p o o l = Pool ( )
f o r r in range (n ) :
C . append ( p o o l . map( f i l l c e l l , r a n g e ( n ∗ r , n ∗ ( r + 1 ) ) ) )
#p r i n t r e s u l t ( )
print calculation ()
PSK: Grzegorz Graczyk i Paweł Tarasiuk
5/5