Concorrenza in Python - Thread

In generale, come sappiamo, il filo è un filo attorcigliato molto sottile di solito del tessuto di cotone o seta e utilizzato per cucire vestiti e simili. Lo stesso termine thread viene utilizzato anche nel mondo della programmazione per computer. Ora, come mettiamo in relazione il filo usato per cucire i vestiti e il filo usato per la programmazione del computer? I ruoli svolti dai due thread sono simili qui. Nei vestiti, il filo tiene insieme il panno e dall'altra parte, nella programmazione del computer, il filo tiene il programma per computer e consenti al programma di eseguire azioni sequenziali o più azioni contemporaneamente.

Threadè la più piccola unità di esecuzione in un sistema operativo. Non è di per sé un programma ma viene eseguito all'interno di un programma. In altre parole, i thread non sono indipendenti l'uno dall'altro e condividono la sezione di codice, la sezione di dati, ecc. Con altri thread. Questi thread sono noti anche come processi leggeri.

Stati di filo

Per comprendere in profondità la funzionalità dei thread, è necessario conoscere il ciclo di vita dei thread o i diversi stati dei thread. In genere, un thread può esistere in cinque stati distinti. I diversi stati sono mostrati di seguito:

Nuovo thread

Un nuovo thread inizia il suo ciclo di vita nel nuovo stato. Tuttavia, in questa fase, non è ancora iniziato e non sono state assegnate risorse. Possiamo dire che è solo un'istanza di un oggetto.

Runnable

Quando il thread appena nato viene avviato, il thread diventa eseguibile, ovvero in attesa di essere eseguito. In questo stato, dispone di tutte le risorse ma l'utilità di pianificazione non ne ha ancora pianificato l'esecuzione.

In esecuzione

In questo stato, il thread avanza ed esegue l'attività, che è stata scelta dall'utilità di pianificazione per l'esecuzione. Ora, il thread può passare allo stato morto o allo stato non eseguibile / in attesa.

Non in esecuzione / in attesa

In questo stato, il thread è in pausa perché è in attesa della risposta di una richiesta di I / O o in attesa del completamento dell'esecuzione di un altro thread.

Morto

Un thread eseguibile entra nello stato terminato quando completa la sua attività o termina in altro modo.

Il diagramma seguente mostra il ciclo di vita completo di un thread:

Tipi di filo

In questa sezione vedremo i diversi tipi di thread. I tipi sono descritti di seguito:

Thread a livello utente

Questi sono thread gestiti dall'utente.

In questo caso, il kernel di gestione dei thread non è a conoscenza dell'esistenza dei thread. La libreria di thread contiene codice per creare e distruggere thread, per passare messaggi e dati tra thread, per pianificare l'esecuzione di thread e per salvare e ripristinare i contesti di thread. L'applicazione inizia con un singolo thread.

Gli esempi di thread a livello utente sono:

  • Thread Java
  • Thread POSIX

Vantaggi dei thread a livello utente

Di seguito sono riportati i diversi vantaggi dei thread a livello utente:

  • Il cambio di thread non richiede privilegi in modalità kernel.
  • Il thread a livello utente può essere eseguito su qualsiasi sistema operativo.
  • La pianificazione può essere specifica dell'applicazione nel thread a livello utente.
  • I thread a livello utente sono veloci da creare e gestire.

Svantaggi dei thread a livello utente

Di seguito sono riportati i diversi svantaggi dei thread a livello utente:

  • In un tipico sistema operativo, la maggior parte delle chiamate di sistema si blocca.
  • L'applicazione multithread non può sfruttare il multiprocessing.

Thread a livello di kernel

I thread gestiti dal sistema operativo agiscono sul kernel, che è un core del sistema operativo.

In questo caso, il kernel gestisce i thread. Non è presente alcun codice di gestione dei thread nell'area dell'applicazione. I thread del kernel sono supportati direttamente dal sistema operativo. Qualsiasi applicazione può essere programmata per essere multithread. Tutti i thread all'interno di un'applicazione sono supportati all'interno di un singolo processo.

Il kernel mantiene le informazioni di contesto per il processo nel suo insieme e per i singoli thread all'interno del processo. La pianificazione dal kernel viene eseguita su base thread. Il kernel esegue la creazione, la pianificazione e la gestione dei thread nello spazio del kernel. I thread del kernel sono generalmente più lenti da creare e gestire rispetto ai thread utente. Gli esempi di thread a livello di kernel sono Windows, Solaris.

Vantaggi dei thread a livello di kernel

Di seguito sono riportati i diversi vantaggi dei thread a livello di kernel:

  • Il kernel può pianificare contemporaneamente più thread dallo stesso processo su più processi.

  • Se un thread in un processo è bloccato, il kernel può pianificare un altro thread dello stesso processo.

  • Le routine del kernel stesse possono essere multithread.

Svantaggi dei thread a livello di kernel

  • I thread del kernel sono generalmente più lenti da creare e gestire rispetto ai thread utente.

  • Il trasferimento del controllo da un thread a un altro all'interno dello stesso processo richiede un cambio di modalità al kernel.

Blocco controllo thread - TCB

Thread Control Block (TCB) può essere definito come la struttura dati nel kernel del sistema operativo che contiene principalmente informazioni sul thread. Le informazioni specifiche del thread memorizzate in TCB evidenziano alcune informazioni importanti su ciascun processo.

Considera i seguenti punti relativi ai thread contenuti in TCB:

  • Thread identification - È l'ID thread univoco (tid) assegnato a ogni nuovo thread.

  • Thread state - Contiene le informazioni relative allo stato (In esecuzione, Eseguibile, Non in esecuzione, Inattivo) del thread.

  • Program Counter (PC) - Punta all'istruzione di programma corrente del thread.

  • Register set - Contiene i valori di registro del thread assegnati loro per i calcoli.

  • Stack Pointer- Indica lo stack del thread nel processo. Contiene le variabili locali nell'ambito del thread.

  • Pointer to PCB - Contiene il puntatore al processo che ha creato quel thread.

Relazione tra processo e thread

Nel multithreading, processo e thread sono due termini strettamente correlati che hanno lo stesso obiettivo di rendere il computer in grado di fare più di una cosa alla volta. Un processo può contenere uno o più thread ma, al contrario, un thread non può contenere un processo. Tuttavia, entrambi rimangono le due unità di base di esecuzione. Un programma, che esegue una serie di istruzioni, avvia sia il processo che il thread.

La tabella seguente mostra il confronto tra processo e thread -

Processi Filo
Il processo è pesante o richiede molte risorse. Il thread è leggero e richiede meno risorse di un processo.
Il cambio di processo richiede l'interazione con il sistema operativo. Il cambio di thread non deve interagire con il sistema operativo.
In più ambienti di elaborazione, ogni processo esegue lo stesso codice ma ha la propria memoria e le proprie risorse di file. Tutti i thread possono condividere lo stesso insieme di file aperti, processi figli.
Se un processo è bloccato, nessun altro può essere eseguito fino a quando il primo processo non viene sbloccato. Mentre un thread è bloccato e in attesa, può essere eseguito un secondo thread nella stessa attività.
Più processi senza l'utilizzo di thread utilizzano più risorse. Più processi con thread utilizzano meno risorse.
In più processi, ogni processo opera indipendentemente dagli altri. Un thread può leggere, scrivere o modificare i dati di un altro thread.
Se ci fosse qualche cambiamento nel processo genitore, non avrà effetto sui processi figli. Se ci fosse qualche cambiamento nel thread principale, potrebbe influenzare il comportamento di altri thread di quel processo.
Per comunicare con i processi di pari livello, i processi devono utilizzare la comunicazione tra processi. I thread possono comunicare direttamente con altri thread di quel processo.

Concetto di multithreading

Come abbiamo discusso in precedenza, il multithreading è la capacità di una CPU di gestire l'uso del sistema operativo eseguendo più thread contemporaneamente. L'idea principale del multithreading è ottenere il parallelismo dividendo un processo in più thread. In un modo più semplice, possiamo dire che il multithreading è il modo per ottenere il multitasking usando il concetto di thread.

Il concetto di multithreading può essere compreso con l'aiuto del seguente esempio.

Esempio

Supponiamo di eseguire un processo. Il processo potrebbe essere l'apertura di MS Word per scrivere qualcosa. In tale processo, un thread verrà assegnato per aprire MS Word e un altro thread sarà richiesto per la scrittura. Ora, supponiamo di voler modificare qualcosa, sarà necessario un altro thread per eseguire l'attività di modifica e così via.

Il diagramma seguente ci aiuta a capire come esistono più thread in memoria:

Possiamo vedere nel diagramma sopra che può esistere più di un thread all'interno di un processo in cui ogni thread contiene il proprio set di registri e variabili locali. Oltre a questo, tutti i thread in un processo condividono variabili globali.

Vantaggi del multithreading

Vediamo ora alcuni vantaggi del multithreading. I vantaggi sono i seguenti:

  • Speed of communication - Il multithreading migliora la velocità di calcolo perché ogni core o processore gestisce thread separati contemporaneamente.

  • Program remains responsive - Consente a un programma di rimanere reattivo perché un thread attende l'input e un altro esegue una GUI allo stesso tempo.

  • Access to global variables - Nel multithreading, tutti i thread di un particolare processo possono accedere alle variabili globali e se c'è qualche cambiamento nella variabile globale, allora è visibile anche ad altri thread.

  • Utilization of resources - L'esecuzione di più thread in ogni programma fa un uso migliore della CPU e il tempo di inattività della CPU si riduce.

  • Sharing of data - Non è richiesto spazio aggiuntivo per ogni thread perché i thread all'interno di un programma possono condividere gli stessi dati.

Contro del multithreading

Vediamo ora alcuni svantaggi del multithreading. Gli svantaggi sono i seguenti:

  • Not suitable for single processor system - Il multithreading trova difficile ottenere prestazioni in termini di velocità di elaborazione su un sistema a processore singolo rispetto alle prestazioni su un sistema multiprocessore.

  • Issue of security - Poiché sappiamo che tutti i thread all'interno di un programma condividono gli stessi dati, quindi c'è sempre un problema di sicurezza perché qualsiasi thread sconosciuto può modificare i dati.

  • Increase in complexity - Il multithreading può aumentare la complessità del programma e il debug diventa difficile.

  • Lead to deadlock state - Il multithreading può portare il programma a un rischio potenziale di raggiungere lo stato di deadlock.

  • Synchronization required- La sincronizzazione è necessaria per evitare l'esclusione reciproca. Ciò porta a più memoria e utilizzo della CPU.