Obiective:
- Introducere în biblioteca
multiprocessing - Crearea și gestionarea proceselor
- Comunicarea între procese
- Sincronizarea proceselor
- Gestionarea resurselor partajate
- Exemple practice și aplicații ale bibliotecii
multiprocessing
Introducere în biblioteca multiprocessing
Biblioteca multiprocessing din Python furnizează o modalitate de a crea și gestiona procese. Aceasta permite rularea paralelă a mai multor sarcini în cadrul unor procese separate. Spre deosebire de firele de execuție, procesele au propriul lor spațiu de adresă și nu sunt afectate de Global Interpreter Lock (GIL) din Python, ceea ce le face mai potrivite pentru sarcini care necesită calcul intensiv.
Crearea și gestionarea proceselor
Pentru a crea un proces, putem defini o funcție care va fi executată de către proces și apoi să inițializăm și să pornim un obiect Process:
import multiprocessing
def afiseaza_mesaj(mesaj):
print(f'Procesul: {multiprocessing.current_process().name} - {mesaj}')
def main():
proces1 = multiprocessing.Process(target=afiseaza_mesaj, args=('Salut!',), name='Proces1')
proces2 = multiprocessing.Process(target=afiseaza_mesaj, args=('Bună ziua!',), name='Proces2')
proces1.start()
proces2.start()
proces1.join()
proces2.join()
main()
În acest exemplu, funcția afiseaza_mesaj va fi executată de către două procese diferite. Funcția start pornește procesele, iar funcția join așteaptă ca procesele să se termine înainte de a continua execuția.
Comunicarea între procese
Comunicarea între procese este importantă atunci când procesele trebuie să partajeze date sau să sincronizeze execuția. Biblioteca multiprocessing oferă diferite metode de comunicare între procese, cum ar fi:
Queue: o coadă care permite proceselor să comunice prin trimiterea și primirea de mesaje.Pipe: un canal de comunicare bidirecțional care permite proceselor să transmită date unul altuia.
Queue
Următorul exemplu ilustrează utilizarea unei cozi pentru a comunica între procese:
import multiprocessing
def produce_elemente(coada):
for i in range(5):
coada.put(i)
print(f'Element adăugat: {i}')
def consuma_elemente(coada):
while not coada.empty():
element = coada.get()
print(f'Element extras: {element}')
def main():
coada = multiprocessing.Queue()
producator = multiprocessing.Process(target=produce_elemente, args=(coada,))
consumator = multiprocessing.Process(target=consuma_elemente, args=(coada,))
producator.start()
consumator.start()
producator.join()
consumator.join()
main()
Pipe
Următorul exemplu ilustrează utilizarea unui pipe pentru a comunica între procese:
import multiprocessing
def produce_elemente(conn):
for i in range(5):
conn.send(i)
print(f'Element trimis: {i}')
conn.close()
def consuma_elemente(conn):
while True:
try:
element = conn.recv()
print(f'Element primit: {element}')
except EOFError:
break
def main():
conn_producator, conn_consumator = multiprocessing.Pipe()
producator = multiprocessing.Process(target=produce_elemente, args=(conn_producator,))
consumator = multiprocessing.Process(target=consuma_elemente, args=(conn_consumator,))
producator.start()
consumator.start()
producator.join()
consumator.join()
main()
Sincronizarea proceselor
Sincronizarea proceselor este importantă atunci când procesele trebuie să aștepte unul pe altul sau să acceseze resurse partajate într-o manieră controlată. Biblioteca multiprocessing oferă diferite primitive de sincronizare, cum ar fi:
Lock: un mecanism de blocare care permite unui singur proces să acceseze o resursă partajată la un moment dat.Semaphore: un mecanism de control al accesului la resurse partajate bazat pe un număr prestabilit de permisiuni.Event: un semnal care permite unui proces să aștepte până când un alt proces setează un eveniment.Condition: un mecanism de semnalizare care permite unui proces să aștepte până când o anumită condiție este îndeplinită de un alt proces.
Lock
Următorul exemplu ilustrează utilizarea unui Lock pentru a sincroniza accesul la o resursă partajată:
import multiprocessing
import time
def actualizeaza_resursa(lock, resursa):
with lock:
resursa.value += 1
time.sleep(0.1)
print(f'Resursa actualizată: {resursa.value}')
def main():
lock = multiprocessing.Lock()
resursa = multiprocessing.Value('i', 0)
procese = [multiprocessing.Process(target=actualizeaza_resursa, args=(lock, resursa)) for _ in range(10)]
for proces in procese:
proces.start()
for proces in procese:
proces.join()
main()
Semaphore
Următorul exemplu ilustrează utilizarea unui Semaphore pentru a limita numărul de procese care accesează o resursă partajată în același timp:
import multiprocessing
import time
def acceseaza_resursa(sem, resursa):
with sem:
resursa.value += 1
print(f'Resursa accesată: {resursa.value}')
time.sleep(1)
resursa.value -= 1
def main():
sem = multiprocessing.Semaphore(3)
resursa = multiprocessing.Value('i', 0)
procese = [multiprocessing.Process(target=acceseaza_resursa, args=(sem, resursa)) for _ in range(10)]
for proces in procese:
proces.start()
for proces in procese:
proces.join()
main()
Event
Următorul exemplu ilustrează utilizarea unui Event pentru a sincroniza execuția a două procese:
import multiprocessing
import time
def asteapta_eveniment(eveniment):
print('Se așteaptă evenimentul...')
eveniment.wait()
print('Evenimentul a fost setat!')
def seteaza_eveniment(eveniment):
time.sleep(3)
eveniment.set()
print('Eveniment setat')
def main():
eveniment = multiprocessing.Event()
proces1 = multiprocessing.Process(target=asteapta_eveniment, args=(eveniment,))
proces2 = multiprocessing.Process(target=seteaza_eveniment, args=(eveniment,))
proces1.start()
proces2.start()
proces1.join()
proces2.join()
main()
Condition
Următorul exemplu ilustrează utilizarea unei Condition pentru a sincroniza execuția a două procese bazate pe o anumită condiție:
import multiprocessing
import time
def asteapta_conditie(conditie, resursa):
with conditie:
while resursa.value != 5:
print('Se așteaptă ca resursa să fie 5...')
conditie.wait()
print('Resursa este 5!')
def modifica_resursa(conditie, resursa):
with conditie:
resursa.value = 5
print('Resursa a fost modificată!')
conditie.notify_all()
def main():
conditie = multiprocessing.Condition()
resursa = multiprocessing.Value('i', 0)
proces1 = multiprocessing.Process(target=asteapta_conditie, args=(conditie, resursa))
proces2 = multiprocessing.Process(target=modifica_resursa, args=(conditie, resursa))
proces1.start()
proces2.start()
proces1.join()
proces2.join()
main()
Exemple practice și aplicații ale bibliotecii multiprocessing
Exemplu 1: Calculul factorialului
import multiprocessing
def calculeaza_factorial