JĘZYK PYTHON - NARZĘDZIE DLA KAŻDEGO NAUKOWCA Marcin Lewandowski [ mlew@ippt.gov.pl ]
HPC 2
Co zrównoleglać (logicznie i fizycznie)? Programowanie z asynchronicznymi zdarzeniami np. interfejs użytkownika, komunikacja sieciowa, obsługa operacji I/O (pliki), etc. Programy których wydajność można zwiększyć przez ukrycie latencji (opóźnień): Długo trwające operacje I/O (zapis/odczyt z plików, komunikacja sieciowa) W czasie trwania tych operacji program może wykonać inną potrzebną pracę Programy intensywnie obliczeniowe: Zagadnienia numeryczne, które silnie wykorzystują jednostki obliczeniowe mogą uzyskać znacznie przyśpieszenie przy wykonywaniu na komputerze z wieloma procesorami/rdzeniami jeśli zadani zostanie podzielone na wątki (lub procesy) 3
Równoległość zadań Źródło: http://en.wikipedia.org/wiki/openmp 4
Co to jest proces? Niezależny kontekst wykonawczy wraz z własną odizolowaną przestrzenią pamięci i zasobami Procesy pomiędzy sobą nie dzielą niczego (z wyjątkiem maszyny ;-) Procesy muszą komunikować się między sobą za pomocą mechanizmów IPC (Inter-Process Communication); do wymiany danych oraz synchronizacji Procesy są ciężkie (wymagają sporo zasobów) 5
Co to jest wątek? Kontekst wykonywania programu Współdzieli pamięć i stan ze swoim rodzicem (procesem w którym żyje). Wątki są lekkie (tj. nie wymagają dużych zasobów) Posiadają własny stos (i prywatne zmienne lokalne) Nie muszą używać IPC do komunikacji z innymi wątkami w procesie Wątki Python = wątki systemu operacyjnego (w Linux POSIX Threads pthreads) 6
Wątek vs. Proces Wątki współdzielą wszystko, dlatego programista musi pilnować wielodostępu do wspólnych danych Procesy nie współdzielą nic, dlatego programista musi explicite zatroszczyć się o współdzielenie danych/stanu pomiędzy procesy 7
Python GIL Python GIL (Global Interpreter Lock) zabezpiecza interpreter Pythona przed wielodostępem, co niestety ogranicza możliwość fizycznego zrównoleglenia. Co robi GIL: GIL zapewnia, że tylko jeden wątek jest wykonywany w danej chwili przez interpreter Pythona (cpythonvm) GIL kontroluje sposób wykonywania wątków. Python ustala jak długo wątek ma być wykonywany (~10 instrukcji). Python wykorzystuje wątki systemu operacyjnego, ale sam kontroluje przekazywanie kontekstu wykonawczego. 8
GIL Co dobrego daje GIL: Realizuje koncepcję kooperatywnej wielozadaniowości Interpreter wie najlepiej kiedy bezpiecznie przełączyć kontekst wykonywania Często jest bardzie efektywny od wielozadaniowości z wywłaszczaniem Może być zwolniony w module C (np. dla długotrwałych operacji I/O) Łatwe kodowanie (nie musimy się pilnować) Łatwą implementację modułów rozszerzeń 9
Moduły Moduł thread _thread (w Python 3+) threading multiprocessing subprocess select Funkcje Nisko poziomowy moduł do wielowątkowości Wysoko poziomowy moduł do wielowątkowości (zbudowany na bazie modułu thread) Wysoko poziomowy moduł do wieloprocesowości Zarządzanie podprocesami Waiting for I/O completion 10
Moduł threading Wysoko poziomowy moduł do realizacji wielowątkowości Zbudowany na nisko poziomowym module thread Działa w oparciu o wątki systemu operacyjnego Równoległość jest ograniczona przez GIL 11
Obiekt threading.thread class threading.thread(group=none, target=none, name=none, args=(), kwargs={}) konstruktor z argumentami nazwanymi: group powinno być None; zarezerwowane dla przyszłych rozszerzeń (ThreadGroup). target wołalny obiekt, który ma być uruchomiony w nowym wątku przez metodę run() name nazwa wątku. Domyślnie tworzona w konstruktorze w postaci Thread-N, gdzie N jest liczbą. args is the argument tuple for the target invocation. Defaults to (). kwargs is a dictionary of keyword arguments for the target invocation. Defaults to {}. Jeśli podklasa nadpisuje konstruktor musi wywołać na samym początku metodę klasy bazowej Thread. init (). Thread.start() startuje wątek. Musi być wywołana tylko raz dla obiektu (zgłasza wyjątek RuntimeException jeśli wywołana więcej razy). Startuje wątek, w którym będzie wywołana metoda run(). Thread.run() metoda realizowana w wątku, która może być przedefiniowana w klasie potomnej. Metoda w klasie bazowej wywołuje obiekt przekazany w konstruktorze (target) z argumentami args i kwargs. Thread.join([timeout]) czeka na zakończenie wątku. Jest to metoda blokująca z zadanym czasem timeout (float w sekundach). W celu określenia stanu wątku po timeout należy użyć metod: isalive(). Metoda join() może być wywoływana wiele razy dla jednego wątku. 12
Obiekt threading.lock Prymitywny obiekt synchronizacyjny typu lock; nie związany z konkretnym wątkiem. Lock ma dwa stany locked i unlocked. Po utworzeniu jest w stanie unlocked. Lock.acquire() Gdy w stanie unlocked zmienia natychmiast stan na locked ; Gdy w stanie locked, acquire() blokuje do momenty wywołania release() w innym wątku i ustawia do stanu locked. Lock.release() powinna być wołana tylko w stanie locked w celu natychmiastowej zmiany stanu na unlocked. Wyjątek RuntimeError jest generowany gdy zwalniany jest obiekt w stanie unlocked. Gdy więcej wątków jest zablokowanych na acquire(), tylko jeden z nich jest odblokowywany dla jednego wywołania release(). Wszystkie te metody są wykonywane atomowo. 13
Obiekt threading.semaphore Jeden z najstarszy obiektów synchronizacyjnych (wymyślony przez W. Dijkstra). Semafor zarządza wewnętrznym licznikiem, który jest zmniejszany przy każdym wywołaniu acquire() i zwiększany przy każdym wywołaniu release(). Licznik jest zawsze >=0 Funkcja acquire() wołana dla Semafora o wartości 0 blokuje się do momentu kiedy inny wątek wywoła release(). class threading.semaphore([value]) tworzy semafor; opcjonalny argument value określa początkową wartość licznika (domyślnie 1). Semaphore.acquire([blocking]) pobiera semafor. Wywołany bez argumentów (lub blocking=ture): jeśli licznik >0 zmniejsza jego wartość o 1 i wraca natychmiast, jeśli licznik=0 blokuje do do momentu wywołania release() w innym wątku. Wywołany z blocking=false: działa w trybie nie blokującym zwracając False natychmiast gdy nie może pobrać semafora lub True gdy udało się go pobrać. Semaphore.release() zwalnia semafor; zwiększając stan licznika o 1. 14
Moduł multiprocessing Interfejs wielowątkowy opartym na procesach Składnia analogiczna do modułu threading: threading : Thread(target=do_work, args=(work_queue,)) multiprocessing: Process(target=do_work, args=(work_queue,)) TRZEBA PAMIĘTAĆ! Procesy nie współdzielą NICZEGO (w szczególności pamięci)! Wymiana danych pomiędzy procesami może odbywać się przez jeden z mechanizmów komunikować IPC (Inter-Process Communication) 15
Wątki Python/C Python może tworzyć wątki w modułach C/C++: Wątki C/C++ są niezależnymi wątkami natywnymi (nie Pythonowymi) i potencjalnie mogą działać równolegle (o ile zwolnimy GIL). W modułach C można programowo zwolnić GIL Inną alternatywą jest utworzenie wielu interpreterów Pythona (w jednym lub wielu procesach) 16
Python IPC & Networking Następujące moduły zapewniają mechanizmy komunikacji IPC: subprocess zarządzanie procesami potomnymi + mechanizm strumieni I/O (popen) socket nisko poziomowy interfejs sieciowy ssl warstwa SSL dla socket signal obsługa sygnałów dla zdarzeń asynchronicznych asyncore asynchroniczne socket asynchat asynchroniczne socket + komenda/odpowiedź signal, subprocess działają tylko dla dwóch procesów na tej samej maszynie inne moduły komunikacji sieciowej mogą służyć do komunikacji wielu procesów na jednej lub wielu maszynach w sieci. 17
Sumowanie liczb pierwszych 3 implementacje EX: hpc Suma liczb pierwszych w zakresie 1-10000 Jednowątkowa 152 sek. Wielowątkowa 425 sek.! Wieloprocesowa xxx sek. Na podstawie: Jesse Noller, Getting started with Concurrency...using Multiprocessing and Threading, PyWorks, Atlanta 2008 18
Sumowanie liczb pierwszych 3 implementacje MT 4 wątki 19
Poważne HPC MPI Message Passing Interface dla systemów z pamięcią rozproszoną (http://www.mcs.anl.gov/research/projects/mpi) OpenMP dla systemów z pamięcią współdzieloną (http://openmp.org) 20
MPI w Python mpi4py MPI jest de facto standardem dla systemów z typu message-passing. MPI jest zestawem API (Application Programmer Interfaces) wywoływalnych przez programy użytkownika w C/C++ (i innych językach) Istnieje wiele implementacji MPI zarówno open source (generyczne) oraz zamknięte i zoptymalizowane do konkretnych maszyn. 21
Implementacje MPI dla Pythona mpi4py (http://mpi4py.scipy.org) API bazuje na bibliotece MPI-2 C++ Działa z open-source implementacjami MPI (MPICH2, Open MPI, MPICH1, LAM) mpi4py pozwala na użycie z Pythona kodu C/C++/Fortran opartego na MPI (za pomocą: Cython, SWIG, F2Py) pympi (http://pympi.sourceforge.net) Starsza implementacja Patrz: http://fperez.org/py4science/2009_siam_cse/mpi4py_ldalcin_bgranger_siam_cse09 22
GPGPU PyCUDA Zapewnia na pełny dostęp do Nvidia CUDA API z Pythona Many abstractions are already provided for you PyOpenCL j.w. ale przez interfejs OpenCL 23
Różne takie inne opcje IPython for parallel computing Bulk Synchronous Parallel (BSP) model sequence of super steps Twisted reactor based architectures MPI (pympi, Pypar, MPI for Python, pypvm) Pyro (distributed object system) Linda (PyLinda) Scientific Python (master/slave computing model) data distribution through call parameters/replication 24
Lektura uzupełniająca Norman Matloff, Programming on Parallel Machines, http://heather.cs.ucdavis.edu/ matloff/parprocbook.pdf Maurice Herlihy, Nir Shavit, The Art of Multiprocessor Programming, Morgan Kaufmann,2008 Rohit Chandra, Ramesh Menon, Leo Dagum, David Kohr, Dror Maydan, Jeff McDonald, Parallel Programming in OpenMP, Morgan Kaufmann, 2000 Barbara Chapman, Gabriele Jost, Ruud van der Pas, Using OpenMP: Portable Shared Memory Parallel Programming, MIT Press, 2007 25
PYTHON + FORTRAN 26
f2py f2py pozwala na automatyczne tworzenie modułów rozszerzeń PYTHON z kodu Fortran 77/90/95: F2py automatycznie generuje funkcje obudowujące (wrappers) dla Pythona z kodu Fortran 77/90/95 Alternatywnie można określić sposób obudowywania procedur w pliku definicji interfejsu. Przykładowa procedura dodająca dwa wektory A i B (pamięć dla wszystkich tablic zapewniona przez procedurę wywołującą): C *** Plik add.f *** SUBROUTINE ZADD(A,B,C,N) C DOUBLE COMPLEX A(*) DOUBLE COMPLEX B(*) DOUBLE COMPLEX C(*) INTEGER N DO 20 J = 1, N C(J) = A(J)+B(J) 20 CONTINUE END Wywołanie f2py: > f2py -m add add.f Co powinno wygenerować moduł o nazwie: addmodule.c, który można następnie skompilować jak każdy inny moduł C do Pythona. 27
Co potrafi f2py Tworzy pliki sygnatur dla kodu/funkcji Fortran (pliki.pyf); sygnatury zawierają wszystkie informacje o funkcji (nazwa, argumenty i ich typy), które są konieczne do utworzenia funkcji opakowującej (wrapper) w C Pliku sygnatur można utworzyć ręcznie lub może być zmodyfikowany po wygenerowaniu Sygnatury mogą być modyfikowane w celu zmiany sposobu przetwarzania argumentów przekazywanych Python->C->Fortran: F2PY śledzi zależności pomiędzy argumentami (sprawa kolejności inicjalizacji) Argumenty mogą być opcjonalne lub niewidoczne, co ułatwia wołanie funkcji z Pythona Generalnie można dowolnie zmienić sygnaturę funkcji Fortran (np. zmiana argumentów ich kolejności, typów). Argumenty będą przetworzone zanim trafią do rzeczywistej funkcji Fortran F2PY automatycznie generuje dokumentację doc (opcjonalnie też LaTeX) dla tworzonych rozszerzeń 28
F2py kompilacja modułu f2py potrafi także kompilować moduł Fortran i moduł rozszerzeń: > f2py -c -m add add.f Skomplilowany moduł jest już dostępny Python: >>> import add >>> print add.zadd. doc zadd - Function signature: zadd(a,b,c,n) Required arguments: a : input rank-1 array( D ) with bounds (*) b : input rank-1 array( D ) with bounds (*) c : input rank-1 array( D ) with bounds (*) n : input int Patrz dokumentacja: NumPy User Guide 29
f2py używany z Pythona f2py jest napisany w Python i może być z niego bezpośrednio używany: Przykład otwórz, skompiluj i użyj : import numpy.f2py as f2py fid = open( add.f ) source = fid.read() fid.close() f2py.compile(source, modulename= add ) import add # use it!!! 30
Materiały dodatkowe F2py example http://websrv.cs.umt.edu/isis/index.php/f2py_example Wrapping Fortran libraries http://www.eurotcl.org/2010/download/eurotcl2010-article- Wrapping_fortran_ArjenMarkus.pdf Interfacing Python with Fortran www-uxsup.csx.cam.ac.uk/courses/pythonfortran/f2py1.pdf www-uxsup.csx.cam.ac.uk/courses/pythonfortran/f2py2.pdf Wrapping Fortran Code for Python with F2PY mentat.za.net/ctpug-numpy/nmarais-f2pytalk.pdf 31