• Non ci sono risultati.

Programmazione multi threaded in Python

N/A
N/A
Protected

Academic year: 2021

Condividi "Programmazione multi threaded in Python"

Copied!
15
0
0

Testo completo

(1)

Programmazione multi

threaded in Python

(2)

Linguaggi dinamici – A.A. 2010/2011

2

Motivazione all'uso dei thread

Pro

Scrittura di applicazioni con molteplici eventi asincroni (GUI)

Riduzione della latenza di servizio mediante l'uso di un pool di server

Speedup di applicazioni intrinsecamente parallele

Contro

Modello di programmazione complicato (gestione della mutua esclusione)

Debugging scomodo

(3)

Il modulo threading

Python mette a disposizione il modulo

threading per la programmazione di applicazioni multithreaded

import threading

Un thread è rappresentato dalla classe Thread, il cui costruttore riceve in ingresso il nome della funzione eseguente il thread

t = threading.Thread(target = worker)

Il metodo start() esegue la funzione in un nuovo thread

t.start()

thread.py

(4)

Linguaggi dinamici – A.A. 2010/2011

4

Passaggio argomenti

È possibile passare un numero arbitrario di argomenti alla funzione da eseguire

Si usa il parametro con nome args della classe Thread

t = threading.Thread(target = worker, \ args = (TUPLA DI ARGOMENTI))

Si definisce la funzione con la signature opportuna

def worker(num):

...

thread_args.py

(5)

Identificazione

Non è strettamente necessario passare un

numero intero quale identificatore di un thread

Ciascun thread ha già un proprio identificatore interno, che può essere ottenuto come segue

Si accede all'oggetto rappresentante il thread corrente tramite il metodo currentThread()

Si invoca il metodo getName() su tale oggetto

name = threading.currentThread().getName()

È possibile impostare un nome arbitrario tramite l'argomento name del costruttore

In caso contrario, il nome assegnato di default è del tipo Thread-<num>

thread_identify.py

(6)

Linguaggi dinamici – A.A. 2010/2011

6

Identificazione

Il modulo logging supporta la stampa del nome del thread nel log degli eventi

È necessario attivare la stampa tramite l'uso della variabile threadName nella stringa di formato del logger

logging.basicConfig(level=logging.DEBUG, \

format='[%(levelname)s] (%(threadName)-10s)' \ ' %(message)s',)

thread_identify_log.py

(7)

Thread demoni

Negli esempi visti finora, il programma

principale ha aspettato il termine dei thread prima di uscire

È possibile marcare un thread come demone

(daemon) in modo tale che il programma non ne aspetti il termine prima di uscire

Si usa il metodo setDaemon() sull'oggetto Thread

d = threading.Thread(name='daemon', target=daemon) d.setDaemon(True)

thread_daemon.py

(8)

Linguaggi dinamici – A.A. 2010/2011

8

Sincronizzazione

Invocando il metodo join() su un oggetto

Thread, il programma principale aspetta che il thread associato esca

t = threading.Thread(name='non-daemon', \ target=daemon)

t.join()

È possibile limitare l'attesa ad un certo numero di secondi (passati in argomento a join())

t.join(1)

Il metodo isAlive() dell'oggetto Thread mi dice se il thread è ancora in esecuzione

is_alive = t.isAlive()

thread_join.py

thread_join_timeout.py

(9)

Enumerazione

Il metodo enumerate() ritorna una lista di tutti i thread attivi

Tale lista contiene il thread attualmente attivo (current) su cui non si può effettuare un join

Va saltato

main_thread = threading.currentThread() for t in threading.enumerate():

if t is main_thread:

continue

logging.debug('joining %s', t.getName()) t.join()

thread_enumerate.py

(10)

Linguaggi dinamici – A.A. 2010/2011

10

Estensione di Thread

Un oggetto di tipo Thread esegue il metodo run() per eseguire la funzione specificata

Si può estendere la classe Thread ed inserire nel metodo run() la funzione da eseguire

class MyThread(threading.Thread):

def run(self):

logging.debug('running') return

thread_subclass.py

(11)

Estensione di Thread

Per passare argomenti al metodo run, è

necessario creare un metodo __init__() in grado di salvare i parametri in altrettanti attributi della classe

Il costruttore della sottoclasse deve invocare esplictamente il costruttore di Thread

Tali attributi saranno acceduti da run()

thread_subc_args.py

(12)

Linguaggi dinamici – A.A. 2010/2011

12

Segnalazione di eventi

I thread possono comunicare fra loro usando oggetti di tipo Event

Un oggetto di tipo Event espone un flag interno, impostabile con i metodi

set(): ad 1

clear(): a 0

Un thread può aspettare l'impostazione ad 1 (set) del flag invocando il metodo wait()

dell'oggetto Event corrispondente

wait() può accettare un timeout di attesa (sec.)

Meccanismo primitivo di variabili condizione (monitor)

Le variabili sono in realtà dei flag

thread_events.py

(13)

Mutua esclusione

Gli oggetti complessi del Python (liste, dizionari, etc.) sono già thread-safe

I tipi di dato di base (int, float) non sono thread- safe

Le classi scritte dal programmatore non sono thread-safe

Per garantire la mutua esclusione, si usa l'oggetto Lock del modulo threading

Metodo acquire(): prova ad acquisire il lock

Metodo release(): rilascia il lock

thread_lock.py

(14)

Linguaggi dinamici – A.A. 2010/2011

14

Semafori

È possibile gestire un pool di risorse di dimensione n in mutua esclusione

Si usa la classe Semaphore() che implementa la struttura dati semaforo

Metodo acquire(): prova ad acquisire il lock

Metodo release(): rilascia il lock

Il costruttore di Semaphore() accetta un numero intero (il numero di slot del pool)

thread_sem.py

(15)

Thread local storage

Ciascun thread può usufruire di un'area privata di memoria per la memorizzazione di

informazioni

Tale area è locale al thread; essa non viene condivisa con gli altri thread in esecuzione

Si invoca la funzione local() del modulo

threading, ottenendo un puntatore alla variabile locale

Si modifica la variabile locale

local_data = threading.local() local_data.value = 1000

thread_local.py

Riferimenti

Documenti correlati

Il programma in C riportato in seguito usa funzioni di libreria definite nello standard POSIX (supportato da quasi tutti i sistemi UNIX) per creare più thread e mandarli in

 In Java è possibile sia creare nuovi thread che fare compiere loro operazioni (alterando il ciclo normale di vita) perché i thread sono oggetti..  Avremo quindi operazioni che

•  Per attivare il thread deve essere chiamato il metodo start() che invoca il metodo run() (il metodo run() non può essere. chiamato direttamente, ma solo

implementazione del concetto di monitor: un oggetto java è associato ad un mutex ricorsivo tramite il quale è possibile disciplinare gli accessi da parte di diversi thread allo

 La funzione DEVE ESSERE CHIAMATA su una variabile mutex che sia già bloccata e di proprietà del thread chiamante. In tal caso la funzione pthread_mutex_unlock sblocca la

▪ Assegnare memoria e risorse per la creazione di nuovi processi è oneroso; poiché i thread condividono le risorse del processo cui appartengono, è molto più con- veniente creare

 Wait (and act) for a single thread within a large group of

• Il metodo run della classe di libreria Thread definisce l’insieme di statement Java che ogni thread (oggetto della classe) eseguirà.. concorrentemente con gli