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