Skip to content

Esercizi su concorrenza e sincronizzazione

Esercizi sulla concorrenza

  1. Scrivere un programma che utilizzi due thread per contare da 0 a 100 in parallelo.
  2. Creare un programma che utilizzi più processi per calcolare la somma dei numeri da 1 a 1000000 utilizzando la concorrenza.
  3. Scrivere un programma che utilizzi thread per scaricare contemporaneamente più file da Internet.
  4. Creare un’applicazione che utilizzi la concorrenza per calcolare il fattoriale di un numero molto grande.
  5. Scrivere un programma che utilizzi processi per eseguire una ricerca parallela in una lista di nomi.
  6. Creare un’applicazione che utilizzi thread per gestire contemporaneamente più connessioni client in una chat room.
  7. Scrivere un programma che utilizzi la concorrenza per calcolare il prodotto scalare tra due vettori di grandi dimensioni.
  8. Creare un’applicazione che utilizzi processi per eseguire una ricerca parallela in una grande base di dati.
  9. Scrivere un programma che utilizzi thread per elaborare contemporaneamente più immagini in formato JPEG.
  10. Creare un’applicazione che utilizzi la concorrenza per calcolare il valore di una funzione matematica utilizzando diverse tecniche di ottimizzazione.

Per questi esercizi, è possibile utilizzare i seguenti moduli Python:

  • threading: per creare e gestire thread
  • multiprocessing: per creare e gestire processi
  • queue: per condividere dati tra thread o processi
  • mutex: per sincronizzare l’accesso a risorse condivise
  • condition: per gestire condizioni di corsa tra thread o processi
  • semaphore: per limitare l’accesso a risorse condivise

Proposte per il laboratorio

  1. Creazione di un’applicazione per la gestione di una lista condivisa tra più processi, utilizzando tecnologie come multiprocessing o concurrent.futures. Gli studenti potrebbero lavorare insieme per creare le funzionalità di base come l’aggiunta e la rimozione di elementi dalla lista e sviluppare un sistema di sincronizzazione utilizzando lock o semafori.
  2. Sviluppo di un’applicazione per la gestione di una chat room condivisa tra più processi, utilizzando tecnologie come multiprocessing o concurrent.futures. Gli studenti potrebbero lavorare insieme per creare le funzionalità di base come l’invio e la ricezione di messaggi e sviluppare un sistema di sincronizzazione utilizzando lock o semafori.
  3. Creazione di un’applicazione per la gestione di una piattaforma di gioco online condivisa tra più processi, utilizzando tecnologie come multiprocessing o concurrent.futures. Gli studenti potrebbero lavorare insieme per creare le funzionalità di base come il movimento dei pezzi sulla scacchiera e sviluppare un sistema di sincronizzazione utilizzando lock o semafori.
  4. Sviluppo di un’applicazione per la gestione di una piattaforma di collaborazione online condivisa tra più processi, utilizzando tecnologie come multiprocessing o concurrent.futures. Gli studenti potrebbero lavorare insieme per creare le funzionalità di base come la condivisione di documenti e sviluppare un sistema di sincronizzazione utilizzando lock o semafori.
  5. Creazione di un’applicazione per la gestione di una piattaforma di streaming video condivisa tra più processi, utilizzando tecnologie come multiprocessing o concurrent.futures. Gli studenti potrebbero lavorare insieme per creare le funzionalità di base come la riproduzione di video e sviluppare un sistema di sincronizzazione utilizzando lock o semafori.

Soluzioni

Presentiamo la soluzione di alcuni dei progetti proposti.

1. lista condivisa

Ecco un esempio di implementazione di una lista condivisa tra più processi in Python utilizzando il modulo multiprocessing:

import multiprocessing
class SharedList(object):
def __init__(self):
self.lock = multiprocessing.Lock()
self.list = []
def add(self, item):
with self.lock:
self.list.append(item)
def remove(self, item):
with self.lock:
if item in self.list:
self.list.remove(item)
def worker(shared_list, name):
for i in range(10):
shared_list.add(f"Item {i} added by {name}")
print(f"{name} added Item {i}")
if __name__ == "__main__":
shared_list = SharedList()
processes = []
# Creazione di due processi
for i in range(2):
p = multiprocessing.Process(target=worker, args=(shared_list, f"Processo {i+1}"))
processes.append(p)
p.start()
# Attesa della fine dei processi
for p in processes:
p.join()
print("Lista condivisa:")
with shared_list.lock:
for item in shared_list.list:
print(item)

In questo esempio, la classe SharedList rappresenta una lista condivisa tra più processi. La lista è protetta da un lock per evitare conflitti di accesso tra i processi.

La funzione worker rappresenta il compito che viene eseguito dai processi. Ogni processo aggiunge 10 elementi alla lista condivisa e stampa un messaggio per indicare l’aggiunta dell’elemento.

Infine, nel blocco if __name__ == "__main__":, vengono creati due processi utilizzando la funzione multiprocessing.Process(). I processi eseguono la funzione worker() passandogli come argomenti la lista condivisa e il nome del processo. Alla fine dell’esecuzione dei processi, viene stampata la lista condivisa.

Nota: questo esempio è solo un esempio di base e potrebbe essere migliorato o adattato alle esigenze specifiche del progetto.

Esercizi sulle tecniche di sincronizzazione

La sincronizzazione è una parte importante della programmazione concorrente in Python. In questa sezione troverai 20 esercizi sulla sincronizzazione, divisi in tre livelli di difficoltà crescente.

Basics

  1. Conta fino a 10: Crea due thread che stampano i numeri da 1 a 10. Utilizza il modulo threading per creare e avviare i thread.
  2. Somma di numeri: Crea due thread che sommano i numeri da 1 a 100. Utilizza il modulo threading per creare e avviare i thread, e utilizza una variabile condivisa per memorizzare il risultato finale.
  3. Timer: Crea un thread che stampa l’ora corrente ogni secondo. Utilizza il modulo threading e la funzione time.sleep() per implementare il timer.

Locks

  1. Conteggio condiviso: Crea due thread che incrementano una variabile condivisa. Utilizza un lock per evitare race conditions.
  2. Accesso condiviso a una risorsa: Crea due thread che accedono a una risorsa condivisa (ad esempio, un file). Utilizza un lock per garantire l’accesso esclusivo alla risorsa.
  3. Protezione di una lista condivisa: Crea una lista condivisa e due thread che aggiungono elementi alla lista. Utilizza un lock per proteggere la lista dalle modifiche simultanee.

Condizioni e eventi

  1. Produttore/consumatore: Crea due thread, uno che produce numeri e l’altro che li consuma. Utilizza una coda condivisa e le condizioni per sincronizzare i thread.
  2. Barriera di sincronizzazione: Crea tre thread che stampano un messaggio in ordine sequenziale. Utilizza una barriera di sincronizzazione per garantire che i thread stampino il messaggio nella giusta sequenza.
  3. Eventi di terminazione: Crea due thread e utilizza gli eventi per gestire la loro terminazione. Il primo thread deve attendere che il secondo termini prima di terminare a sua volta.

Sincronizzazione avanzata

  1. Semafori: Crea tre thread che accedono a una risorsa condivisa. Utilizza i semafori per controllare l’accesso alla risorsa e prevenire race conditions.
  2. Lock con timeout: Modifica l’esercizio 4 del livello 2 in modo da utilizzare un lock con timeout per evitare deadlocks.
  3. Thread pool: Crea una pool di thread e utilizza le condizioni per gestire i task in ingresso e in uscita dalla pool.

Mix

  1. Produttore/consumatore con semafori: Modifica l’esercizio 1 del livello 4 in modo da utilizzare i semafori invece delle condizioni per sincronizzare i thread.
  2. Barriera di sincronizzazione con eventi: Modifica l’esercizio 3 del livello 3 in modo da utilizzare le barriere di sincronizzazione invece degli eventi per gestire la terminazione dei thread.
  3. Lock condiviso tra processi: Crea due processi che accedono a una risorsa condivisa. Utilizza un lock condiviso tra i processi per garantire l’accesso esclusivo alla risosa.
  4. Sincronizzazione con file di lock: Crea due thread che scrivono su un file condiviso. Utilizza un file di lock per sincronizzare l’accesso al file e prevenire race conditions.
  5. Sincronizzazione con pipe: Crea due processi che comunicano attraverso una pipe. Utilizza le pipe per sincronizzare i processi e scambiare dati tra di loro.