La concurrència és un concepte clau en la programació moderna, especialment quan es tracta de millorar el rendiment i la capacitat de resposta de les aplicacions. En aquest tema, explorarem com Python gestiona la concurrència mitjançant fils (threads) i processos (processes).

Objectius del Tema

  • Entendre la diferència entre fils i processos.
  • Aprendre a crear i gestionar fils en Python.
  • Aprendre a crear i gestionar processos en Python.
  • Conèixer les eines i biblioteques que Python ofereix per treballar amb concurrència.

  1. Diferència entre Fils i Processos

Fils (Threads)

  • Definició: Un fil és la unitat més petita d'execució dins d'un procés. Els fils d'un mateix procés comparteixen el mateix espai de memòria.
  • Avantatges:
    • Menor sobrecàrrega en la creació i destrucció.
    • Compartició de memòria fàcil entre fils.
  • Desavantatges:
    • Potencials problemes de sincronització (race conditions).
    • Limitació del GIL (Global Interpreter Lock) en Python, que impedeix l'execució concurrent de múltiples fils en un sol procés.

Processos (Processes)

  • Definició: Un procés és una instància d'un programa en execució. Cada procés té el seu propi espai de memòria.
  • Avantatges:
    • Execució realment paral·lela en sistemes multiprocessador.
    • Aïllament de memòria, evitant problemes de sincronització.
  • Desavantatges:
    • Major sobrecàrrega en la creació i destrucció.
    • Comunicació entre processos més complexa.

  1. Treballant amb Fils en Python

Creació de Fils

Python proporciona el mòdul threading per treballar amb fils. A continuació, es mostra un exemple bàsic de com crear i executar un fil:

import threading

def treballar():
    print("El fil està treballant")

# Crear un fil
fil = threading.Thread(target=treballar)

# Iniciar el fil
fil.start()

# Esperar que el fil acabi
fil.join()

Sincronització de Fils

Per evitar problemes de sincronització, podem utilitzar bloquejos (locks):

import threading

bloqueig = threading.Lock()

def treballar():
    with bloqueig:
        print("El fil està treballant amb bloqueig")

fil = threading.Thread(target=treballar)
fil.start()
fil.join()

  1. Treballant amb Processos en Python

Creació de Processos

Python proporciona el mòdul multiprocessing per treballar amb processos. A continuació, es mostra un exemple bàsic de com crear i executar un procés:

import multiprocessing

def treballar():
    print("El procés està treballant")

# Crear un procés
procés = multiprocessing.Process(target=treballar)

# Iniciar el procés
procés.start()

# Esperar que el procés acabi
procés.join()

Comunicació entre Processos

Podem utilitzar cues (queues) per comunicar-nos entre processos:

import multiprocessing

def treballar(cua):
    cua.put("Missatge del procés")

# Crear una cua
cua = multiprocessing.Queue()

# Crear un procés
procés = multiprocessing.Process(target=treballar, args=(cua,))

# Iniciar el procés
procés.start()

# Esperar que el procés acabi
procés.join()

# Llegir el missatge de la cua
missatge = cua.get()
print(missatge)

  1. Comparació entre Fils i Processos

Característica Fils Processos
Espai de Memòria Compartit Aïllat
Creació/Destrucció Ràpida Més lenta
Comunicació Fàcil (memòria compartida) Més complexa (IPC)
Execució Paral·lela Limitada pel GIL Realment paral·lela
Sincronització Necessària (locks) Menys necessària

Exercicis Pràctics

Exercici 1: Crear i Gestionar Fils

Crea un programa que iniciï tres fils, cadascun dels quals imprimeixi un missatge diferent. Assegura't que tots els fils acabin abans que el programa finalitzi.

Exercici 2: Crear i Gestionar Processos

Crea un programa que iniciï dos processos, cadascun dels quals imprimeixi un missatge diferent. Utilitza una cua per enviar un missatge des de cada procés al procés principal.

Exercici 3: Sincronització de Fils

Crea un programa que iniciï dos fils que incrementin una variable compartida 1000 vegades cadascun. Utilitza un bloqueig per assegurar-te que la variable es modifica de manera segura.

Solucions

Solució 1: Crear i Gestionar Fils

import threading

def treballar(missatge):
    print(missatge)

fils = []
missatges = ["Fil 1", "Fil 2", "Fil 3"]

for missatge in missatges:
    fil = threading.Thread(target=treballar, args=(missatge,))
    fils.append(fil)
    fil.start()

for fil in fils:
    fil.join()

Solució 2: Crear i Gestionar Processos

import multiprocessing

def treballar(missatge, cua):
    print(missatge)
    cua.put(f"Missatge del {missatge}")

cua = multiprocessing.Queue()
processos = []
missatges = ["Procés 1", "Procés 2"]

for missatge in missatges:
    procés = multiprocessing.Process(target=treballar, args=(missatge, cua))
    processos.append(procés)
    procés.start()

for procés in processos:
    procés.join()

while not cua.empty():
    print(cua.get())

Solució 3: Sincronització de Fils

import threading

bloqueig = threading.Lock()
variable_compartida = 0

def incrementar():
    global variable_compartida
    for _ in range(1000):
        with bloqueig:
            variable_compartida += 1

fils = [threading.Thread(target=incrementar) for _ in range(2)]

for fil in fils:
    fil.start()

for fil in fils:
    fil.join()

print(f"Valor final de la variable compartida: {variable_compartida}")

Conclusió

En aquest tema, hem explorat els conceptes de concurrència en Python mitjançant fils i processos. Hem après a crear i gestionar fils i processos, així com a sincronitzar fils per evitar problemes de concurrència. També hem vist com comunicar-nos entre processos utilitzant cues. La comprensió d'aquests conceptes és fonamental per escriure aplicacions eficients i responsives.

Curs de Programació en Python

Mòdul 1: Introducció a Python

Mòdul 2: Estructures de Control

Mòdul 3: Funcions i Mòduls

Mòdul 4: Estructures de Dades

Mòdul 5: Programació Orientada a Objectes

Mòdul 6: Gestió de Fitxers

Mòdul 7: Gestió d'Errors i Excepcions

Mòdul 8: Temes Avançats

Mòdul 9: Proves i Depuració

Mòdul 10: Desenvolupament Web amb Python

Mòdul 11: Ciència de Dades amb Python

Mòdul 12: Projecte Final

© Copyright 2024. Tots els drets reservats