Algoritmi Avanzati a.a.2014/2015 Prof.ssa Rossella Petreschi Lezione n°9
Idea Variabili: N: numero dei processori y: elemento da cercare X = (x 1, x 2, …, x n ), tale che x 1 x 2 … x n : vettore in cui cercare y l ed r (inizializzati a 0 ed n rispettivamente): estremi del vettore su cui si lavora; q 0,…q N+1 (relative a ciascun processore + 2 aggiuntive): indice degli elementi da analizzare; c 0,…c N+1 (inizializzate a 0, c N+1 inizializzata ad 1): identificatori del sottovettore su cui iterare. Input: X, y Output: i t.c. x i y x i+1 Passo 1: dividi iterativamente il vettore in sottovettori più o meno bilanciati finché il numero di elementi nel sottovettore identificato non è N e controlla se X[q i ]=y; Passo 2: controlla se nel sottovettore di dimensione N è presente l’elemento cercato.
Algoritmo P 1 :c 0 = 0; c N+1 = 1; l=0; r=n+1; while (r-l) > N do P j :for j = 1 to N pardo if j = 1 then q 0 = l; q N+1 = r q j = l + j (r-l) / (N+1) if y = X[ q j ] then return q j else if y > X[ q j ] then c j = 0 else c j = 1 if c j < c j+1 then l = q j ; r = q j+1 if j = 1 and c 0 < c 1 then r = q 1 P j :for j = 1 to N pardo if y = X[ l+j ] then return l+j else if y > X[ l+j ] then c j = 0 else c j = 1 if c j < c j+1 then return l+j if j = 1 and c 0 < c 1 then return l Passo 1 Passo 2
Esempio x -- n = 14 N = 2 y = 37 q0q0 q1q1 q2q2 q3q c0011 lr x q0q0 q1q1 q2q2 q3q c0001 lr x c0011 lr Passo 2 return 9
Complessità dell’algoritmo Ciascuna iterazione del Passo 1 richiede tempo O(1). Dimensione del sottovettore alla iterazione i-esima: s i+1 = s i / (N+1) = s 0 / (N+1) i = n+2 / (N+1) i Numero totale di iterazioni: log N+1 (n+2) = log 2 (n+2) / log 2 (N+1) Il Passo 2 richiede tempo costante. Tempo complessivo richiesto dall’algoritmo: O(log 2 (n+2) / log 2 (N+1)). Il modello di PRAM è CREW perché tutti gli N processori accedono contemporaneamente alle variabili y, l, r e c. Quando N = O(1), il costo complessivo dell’algoritmo è O(log n): pari all’ottimo nel sequenziale. Quando N = O(n) il tempo diventa costante.
Sistema Distribuito Un Sistema Distribuito è un insieme interconnesso di computer, processi o processori, ciascuno definito in modo autonomo. Un sistema distribuito si può pensare semplicemente come un sistema fisico (computer connessi da una rete) o più in generale come un sistema logico: insieme di processi connessi da un meccanismo di scambio di messaggi. “... è un sistema in cui la caduta di un computer del quale ignoravi persino l’esistenza, può rendere il tuo computer inutilizzabile” Lensi Lamport “... è un modo di organizzare e considerare una famiglia di risorse indipendenti e possibilmente distanti (o debolmente connesse), come se facessero parte di un unico grande pacchetto” Andrew Tannenbaum
Trasmissione dell’informazione Nei sistemi distribuiti, la trasmissione dell’informazione assume un ruolo fondamentale. A seconda del sistema preso in considerazione, la rete di interconnessione può consistere in connessioni punto a punto (in tal caso ogni connessione gestisce il traffico esclusivamente fra due processori) o in canali di trasmissione (broadcast channels) che distribuiscono l’informazione a tutti i processori appartenenti ad un agglomerato (cluster) predefinito. I processori non condividono fisicamente alcuna memoria e quindi lo scambio di informazioni fra essi deve per forza passare lungo la specifica rete di interconnessione.
Task Definiamo task un frammento di codice sequenziale che deve essere eseguito da un singolo processore. Quando due task debbono comunicare fra loro durante l’esecuzione, ma i processori che li stanno eseguendo non sono connessi direttamente nella rete, non c’è modo di effettuare tale comunicazione in modo diretto. Ogni processore nel sistema deve pertanto, sia eseguire il task che gli è stato assegnato, sia ridistribuire l’informazione secondo le necessità del caso. Queste due operazioni, per quanto possibile, non devono interferire fra di loro. In tal modo ogni processore viene visto dal sistema come una coppia di entità logiche che lavorano in modo indipendente: l’entità di processo che esegue il proprio compito e l’entità di comunicazione che trasmette l’informazione nella rete.
Differenza fra sistema distribuito e parallelo Sistema distribuitoSistema parallelo sistema multiutente che si riferisce ad ambienti di lavoro di tipo collaborativi è pensato per essere usato da un singolo utente o processo per garantire la massima velocizzazione di una singola applicazione computer, processi o processori non omogenei e asincroni processori omogenei sincroni computer, processi o processori fra loro autonomi processori usati insieme per un’unica computazione problemi di sicurezza connessi alla rete (perdita di messaggi, cadute di sitema, condivisione dei dati, etc…) in genere è considerato come un sistema fisicamente e logicamente inaccessibile
Algoritmo Distribuito Un algoritmo distribuito D si può rappresentare come un grafo G = (P, C), dove l’insieme dei nodi è l’insieme dei processori e l’insieme degli spigoli orientati è un insieme di canali di comunicazione (generalmente unidirezionali). Tutti i processori, con l’eccezione di un sottoinsieme al quale è permesso di mandare messaggi “spontaneamente”, sono reattivi, ovvero eseguono un qualunque task solo come risposta al ricevimento di un messaggio da un altro task. Un solo blocco di processori P init può inizialmente eseguire un task a scopo di inizializzazione.
Schema base di un algoritmo distribuito begin P init : exec eventuali operazioni di inizializzazione; send messaggio ai vicini repeat P i :receive messaggio M e B M è vero exec qualche operazione send messaggi ai vicini until un segnale di terminazione globale arriva a D end La operazione di send invia un messaggio su uno o più canali di comunicazione uscenti da P i. Ogni processore ha una coda di messaggi ricevuti. La receive estrae un messaggio dalla coda di P i.
Complessità distribuita complessità dei messaggi (M d ): è il numero totale di messaggi spediti tra nodi vicini durante la computazione; complessità temporale (T d ): tempo speso per la comunicazione durante la computazione del caso peggiore fino a quando l’output richiesto è stato raggiunto (o il sistema va in halt)
Sistemi sincroni e asincroni Sistema sincronoSistema asincrono Un messaggio spedito da un nodo ad un suo vicino arriva sempre in tempo costante La trasmissione dei messaggi ha durata variabile L'assenza di segnale è informazione L'assenza di segnale non fornisce informazione La computazione locale ha costo zero
Complessità temporale Per quanto riguarda la complessità temporale, nel modello sincrono il suo calcolo si riduce essenzialmente a contare il numero delle pulsazioni che trascorrono durante la computazione; nel modello asincrono il suo calcolo corrisponde al numero di messaggi nella più lunga catena casuale della forma “ricevi un messaggio e spedisci un messaggio come conseguenza”, calcolata su tutte le possibili esecuzioni dell’algoritmo e su tutte le possibili strutture del grafo G. Come sempre, queste misure sono considerate nel caso peggiore e in forma asintotica in funzione di n e m, nodi e archi di G.
La rete ad anello Si suppone che i nodi dell’anello siano identificati da valori diversi scelti in un insieme di positivi qualunque, senza alcun vincolo di ordine. L’anello si considera unidirezionale. I singoli processi non conoscono la dimensione della rete; sono però in grado di distinguere fra vicino sinistro e vicino destro.
Broadcast in un sistema distribuito ad anello P 0 ha l’informazione da distribuire nella variabile inf begin P 0 :send inf al successore repeat P i :receive inf da predecessore send inf al successore until P 0 riceve messaggio dal predecessore end In una rete ad anello ad n nodi, vengono inviati n messaggi in n passi P0P0 P2P2 P n-1 P1P1 P3P3
Broadcast in una qualsiasi rete a connessione fissa Assumiamo connessioni unidirezionali e rete aciclica begin P init :N init = { q : q è un vicino di P init } send messaggio ad ogni q in N init repeat P i :receive messaggio da un vicino p N i = { q : q è un vicino di P i } send messaggio ad ogni q in N i until … end Si ricorda che P i invia lo stesso messaggio a tutti i suoi vicini contemporaneamente però sia i processori sia i canali di comunicazione sono eterogenei, quindi il tutto è asincrono. In una rete di n nodi, vengono inviati O(m) messaggi in O(d) passi m = numero archi d = diametro della rete Manca il segnale di terminazione globale P init
Broadcast con eco in una qualsiasi rete a connessione fissa Per risolvere il problema della terminazione si usa l’eco e servono connessioni bidirezionali begin P eco :N eco = { q : q è un vicino di P eco } send messaggio ad ogni q in N eco cont eco = 0 while cont eco < | N eco | receive messaggio da un vicino incrementa cont eco termina P i≠ eco :receive messaggio da un vicino p che chiamo padre N i = { q p : q è un vicino di P i } send messaggio ad ogni q in N i cont i = 0 while cont i < | N i | receive messaggio da un vicino incrementa cont i send messaggio al padre p end
Complessità del broadcast con eco Durante una esecuzione dell’algoritmo di Broadcast con eco vengono inviati in totale M d = 2m messaggi (2 per ogni arco) e l’algoritmo richiede T d = O(d) passi di comunicazione (dove d è il diametro della rete).
Esempio broadcast con eco 1 0/4 0/2 0/4 1/2 2/2 1/4 Processore non raggiunto dal Broadcast Processore raggiunto dal Broadcast (all’interno sono riportati i valori di cont i e di |N i |) Messaggio di Broadcast Processore che ha ricevuto conferma da tutti i vicini (incluso l’eco) Messaggio di eco Passo 1: Inizializzazione Passo 2 Ogni processore manda solo due messaggi: uno di broadcast ai suoi vicini dopo averlo ricevuto dal padre (prime istruzioni del processore Pi) e uno di eco dopo aver ricevuto messaggi da tutti i suoi vicini (al termine del ciclo while). La distinzione tra messaggi di broadcast e di eco è soltanto logica, di fatto i messaggi sono identici. Nell’esempio, al passo 2, abbiamo due tipi di processori che ricevono messaggi: quelli ancora in attesa del padre e quelli che già sono nel ciclo while. In particolare il processore Pc riceve un messaggio sia da Pa che da Pb. Supponiamo che Pa sia il padre, in quanto il messaggio da lui inviato è finito in testa alla coda. Pc invierà subito un messaggio a Pb, che incrementa il suo contatore, mentre invierà un messaggio a Pa soltanto dopo aver ricevuto Nc messaggi dai suoi vicini (incluso quello inviato da Pb). Il contatore di Pd ha già raggiunto il suo valore massimo e quindi Pd è pronto per mandare un eco al padre. PaPa PbPb PcPc P eco PdPd
Esempio broadcast con eco 2 4/4 2/2 2/4 4/4 0/2 1/4 2/2 1/4 2/2 1/1 2/2 Passo 4 Passo 3 Passo 5Passo 6
Elezione del Leader su una rete ad anello Algorithm LEA (Leader Election su un anello) begin Pinit=i:stato = ignoto stato finale =F send i al succ repeat P i :receive inf if inf = halt and stato = ignoto then send halt al succ if inf = halt and stato = leader then stato finale =T if inf > i then send inf al succ if inf = i then stato = leader send halt al succ until inf = halt and stato finale =T end O(n 2 ) messaggi in n passi Si noti che l’intero algoritmo termina quando il segnale di halt torna al leader.
Esempio di funzionamento di LEA Passo 1 Passo 4Passo 3Passo 2 inizializzazione LEADER
Correttezza e complessità dell’algoritmo LEA Teorema: L’algoritmo LEA risolve il problema dell’elezione del leader su un sistema distribuito sincrono ad anello. Esso richiede complessità temporale n e complessità dei messaggi O(n 2 ). Dimostrazione: La correttezza si basa sui seguenti due fatti: Fatto 1: Nessun processore, eccetto quello di indice massimo, raggiunge lo stato di leader. Fatto 2: Dopo n passi lo stato del processore di indice massimo è quello di leader. Dal Fatto 2 si deduce la complessità temporale che implica anche quella dei messaggi.
Un solo iniziatore Algorithm LEA (Leader Election su un anello con un solo inizializzatore init) begin P i :stato = ignoto P init : send init al succ repeat P i : receive inf if inf = halt and stato = ignoto then send halt al succ if inf = i then stato = leader send halt al succ if inf < i then inf = i send inf al succ until inf = halt and stato =leader end O(n) messaggi in O(n) passi
K-vicinato DEFINIZIONE: Il k-vicinato di un processore p in un anello è dato dall’insieme dei processori che sono a distanza k da p nell’anello (sia da sinistra che da destra). Il k-vicinato chiuso di un processore include esattamente 2k+1processori
Algoritmo per l’elezione del Leader con l’ausilio del k-vicinato ALGORITMO (Si procede per fasi) In ogni fase k un processore cerca di diventare leader temporaneo del suo 2 k - vicinato. Solo i processori che riescono ad essere leader temporanei nella fase k diventano poi attivi nella fase k+1. Si dimostra che le fasi sono al più O(logn) Notare che l’anello ora è considerato bidirezionale
Leader temporaneo Nella fase 0 tutti i processori mandano il loro identificativo al proprio vicino di dx e al proprio vicino di sx. Diventano Leader temporanei nella fase 0 (e quindi processori attivi nella fase 1) tutti quei processori il cui identificativo è maggiore sia dell’identificativo del vicino dx che dell’identificativo del vicino sx. Alla generica fase l, ogni processore p i che è risultato Leader temporaneo alla fase l-1 manda il valore del proprio identificativo i al suo 2 l -vicinato. Solo i vicini con identificativo minore di i, mandano a p i una risposta. Se p i riceve risposta da tutto il suo vicinato, p i diviene Leader alla fase l e attivo alla fase l+1
Cosa ricevo e cosa invio P j invia: (test,j,l,d): dove test esprime che il messaggio è per verificare se P j può diventare leader temporaneo alla fase l dopo essersi confrontato con tutti i suoi vicini, da quelli a distanza 1 fino a quelli a distanza 2 l, sia a destra che a sinistra. d inizialmente è pari ad 1 ed indica in ogni istante temporale a che distanza da j sono i vicini con cui ci si sta confrontando. (risp,k,l): quando P j vuole comunicare che si dichiara perdente e, per quanto lo riguarda, P k può essere leader nella fase l, e quindi attivo nella fase l+1. P k riceve: (test,j,l,d): P j e P k si confrontano. P k si attiva solo se P k < P j. Se la sua distanza d da P j è minore di 2 l deve far da tramite per passare l’informazione test al processore suo vicino a distanza d+1 da P j, altrimenti deve chiedere al suo vicino a distanza d-1 da P j di far da tramite per far sapere a P j che, per quanto lo riguarda, può essere leader nella fase l. (risp,j,l): P k deve distinguere se lui stesso è P j o no. Se non è P j deve solamente far passare l’informazione al suo vicino nel cammino fra lui e P j. Se invece è P j, allora deve aspettare la risposta dal vicinato nell’altra direzione. Se questa risposta arriva, si dichiara leader temporaneo alla fase l, altrimenti si deve dichiarare perdente.
Algoritmo per l’elezione del Leader con l’ausilio del k-vicinato Algorithmo LEAK (Leader Election su un anello con k-vicinato) begin P init=i :stato = ignoto; send (test,i,0,1) al vicino sx e al vicino dx; repeat P i :if receive (test,j,l,d) from sx (dx) if j = id then stato = leader; send halt to sx if j > i and d ≧ 2 l then send (risp,j,l) to dx(sx) if j > i and d < 2 l then send (test,j,l,d+1) to sx(dx) if receive (risp,j,l) from sx (dx) if j i then send (risp,j,l) to dx(sx) if hai già ricevuto (risp,j,l) from dx(sx) then send (test,j,l+1,1) to dx and sx if receive (halt) and stato = ignoto then send (halt) to sx until inf = halt e and stato = leader end Nota: per non appesantire la scrittura dell’algoritmo sono state dettagliate solo alcune parti dell’algoritmo.
Correttezza e complessità dell’algoritmo LEAK Anche in questo caso la correttezza dell’algoritmo si basa sul fatto che nessun processore, eccetto quello di indice massimo, raggiunge lo stato di Leader globale. Complessità dei messaggi(M d ) = numero di fasi (ovvero T d ) moltiplicato per numero di messaggi trasmessi in ogni singola fase: Numero di fasi: al termine della generica fase l, il massimo numero di processori Leader temporanei(Lt) è dato da n/(2 l +1) dato che, se un processore p i risulta Lt, tutti i processori nel suo 2 l - vicinato debbono avere identificativo minore di i. Ne consegue che fra due Lt, p i e p j, ci debbono essere almeno 2 l processori (il vicinato sx dell’uno e quello dx dell’altro). Da queste considerazioni ne consegue che il numero delle fasi sarà al più dell’ordine di logn. Messaggi trasmessi in ogni singola fase: ogni processore attivo al più trasmette 2x 2 l messaggi di test, uno ad ogni processore del suo vicinato. Analogamente può ricevere al più 2x 2 l messaggi di risp, uno da ogni processore del suo vicinato, quindi n/(2 l +1) x 2 x 2 l <=4n Pertanto il numero totale di messaggi trasmessi sarà dato da O(nlogn)