esempio thread in python: calcolo della matrice prodotto

Vediamo ora un esempio di programma per il calcolo di una matrice prodotto in python che esegue il calcolo di ogni elemento in un thred differente

Matematicamente l’elemento C{}under{i,j} della matrice prodotto è definito da

C{}under{i,j}=sum{n=1}{K}{A{}under{i,n}B{}under{n,j}}

Il programma andrà quindi a definire una lista di thread, aspetterà il completamento di tutti e scriverà a avideo la matrice prodotto.
Inserisco per prima cosa le tre matrici coinvolte: A e B sono le matrici che verranno moltiplicate e C sarà usato per contenere il risultato.
Il programma è in grado di gestire anche matrici di dimensioni differenti anche se A e B qui hanno una dimensione specifica. Si può quindi rieseguire l’esempio semplicemente sostituendo A e B o modificandolo per andare a leggere da disco i valori.

if __name__ == "__main__":
   """ inizializzo le tre matrici"""
   # definisco le matrici iniziali
   A = [ [1,1,1], [1,1,1]]
   B = [ [1,1], [1,1],[1,1]]
   C = [[0 for j in range(len(A))] for i in range(len(B[0]))]

Definisco una lista in cui raggrupperò i thread che in questo caso utilizzerò per assicurarmi che tutti i thread hanno completato la loro attività prima di stampare il risultato.
Il codice contiene anche, commentata, la definizione di un oggetto lock che può essere utilizzato per controllare la sincronizzazione dei thread. In questo caso però non è utile dato che le operazioni eseguite dai vari thread sono indipendenti.

   
   # acquisizione del lock
   # threadLock = threading.Lock()
   threads = []

Definisco e avvio poi i vari thread sfruttando un’apposita classe myThread che descriveremo più sotto nel dettaglio.

   # avvio in thread per ogni elemento della nuova matrice
   thread_id = 0
   for row in range( len(A) ):
      for column in range( len(B[0]) ):  
         # Create new threads
         threads_a = myThread(thread_id, "Thread-"+str(row)+"_"+str(column), row, column)
         # Start new Threads
         threads_a.start()
         # Add threads to thread list
         threads.append(threads_a)
         thread_id = thread_id + 1

attendo il completamento di tutti i thread

   #    Wait for all threads to complete
   for t in threads:
      t.join()

stampo in fine il risultato

   for i,v in enumerate(C):
      print(C[i])

Passiamo ora alla classe myThread che è costituita ridefinendo la classe threading.Thread.
In particolare ridefiniamo due funzioni: un costruttire e la funzione run che viene eseguita dal thread avviato con lo start().
Il costruttore si limita a definire nell’oggetto alcune variabili passate per argomento

class myThread( threading.Thread ):
   def __init__(self, threadID, name, row, column):
      threading.Thread.__init__(self)
      self.threadID = threadID
      self.name = name
      self.row = row
      self.column = column

la funzione run invece contiene tutto il calcolo dell’elemento di matrice

   def run( self ):
      print ( "Starting " + self.name )
      # Get lock to synchronize threads
      # threadLock.acquire()
      # calculate matrix element
      self.totale = 0
      for a in range(len(A[self.row])):
         for b in range( len(B) ):
            if( a == b ): 
               self.totale = self.totale + A[self.row][a] * B[b][self.column]
            #print("{:s}, self.totale = {:d}".format(self.name, self.totale) )

      C[self.row][self.column] = self.totale
      # Free lock to release next thread
      # threadLock.release()

Decommentando la riga print si può vedere come i thread procedono in parallelo.

Riporto sotto il codice completo

class myThread( threading.Thread ):
def __init__(self, threadID, name, row, column):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.row = row
self.column = column
def run( self ):
print ( "Starting " + self.name )
# Get lock to synchronize threads
# threadLock.acquire()
# calculate matrix element
self.totale = 0
for a in range(len(A[self.row])):
for b in range( len(B) ):
if( a == b ):
self.totale = self.totale + A[self.row][a] * B[b][self.column]
#print("{:s}, self.totale = {:d}".format(self.name, self.totale) )

C[self.row][self.column] = self.totale
# Free lock to release next thread
# threadLock.release()

if __name__ == "__main__":
""" inizializzo le tre matrici"""
# definisco le matrici iniziali
A = [ [1,1,1], [1,1,1]]
B = [ [1,1], [1,1],[1,1]]
C = [[0 for j in range(len(A))] for i in range(len(B[0]))]

# acquisizione del lock
# threadLock = threading.Lock()
threads = []

# avvio in thread per ogni elemento della nuova matrice
#numThread = A.len() * B[0].len()
thread_id = 0
for row in range( len(A) ):
for column in range( len(B[0]) ):
# Create new threads
threads_a = myThread(thread_id, "Thread-"+str(row)+"_"+str(column), row, column)
# Start new Threads
threads_a.start()
# Add threads to thread list
threads.append(threads_a)
thread_id = thread_id + 1

# Wait for all threads to complete
for t in threads:
t.join()

for i,v in enumerate(C):
print(C[i])

			

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *