Nella progettazione di applicazioni scalabili multithread e distribuite vengono utilizzati pattern che garantiscono la sicurezza durante l'accesso parallelo e l'interazione efficiente tra i componenti.
Pattern "Attore" — è un modello in cui ogni unità (attore) incapsula uno stato e interagisce con gli altri solo attraverso messaggi asincroni. Questo esclude le condizioni di gara poiché l'attore gestisce autonomamente i messaggi in arrivo in ordine.
Pattern "Coda dei messaggi" — è una soluzione architetturale in cui componenti separati inviano dati a una coda di messaggi, da cui vengono estratti dai lavoratori. Ciò garantisce il buffering delle attività, la separazione delle velocità di invio e di esecuzione e la resilienza ai sovraccarichi.
Esempio di "Attori" in Scala (Akka):
class SimpleActor extends Actor { def receive = { case "ping" => sender() ! "pong" } }
Esempio di coda dei messaggi in Python (RabbitMQ/Pika):
import pika connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) channel = connection.channel() channel.queue_declare(queue='tasks') channel.basic_publish(exchange='', routing_key='tasks', body='Hello')
Caratteristiche chiave:
È possibile passare oggetti di stato condiviso (Shared State) tra attori?
No, gli attori non dovrebbero condividere stato. Comunicano solo attraverso messaggi, altrimenti si perde il vantaggio dell'isolamento e si corre il rischio di condizioni di gara dei dati.
La coda dei messaggi garantisce l'ordine di consegna per tutti i sottoscrittori?
No, viene garantito solo l'ordine all'interno di una singola coda per un singolo consumatore. Durante la scalabilità (più consumatori), l'ordine non è garantito tra i riceventi.
Gli attori e le code dei messaggi sono concorrenti l'uno dell'altro?
No, vengono spesso combinati: attori per la logica interna (ad esempio, all'interno di un nodo) e code dei messaggi per lo scambio di attività tra servizi o macchine.