CodeGym /Corso Java /Python SELF IT /Multithreading

Multithreading

Python SELF IT
Livello 25 , Lezione 0
Disponibile

1.1 Storia della creazione

L'umanità spesso arriva all'idea di costruire un nuovo progetto grandioso, che offuschi tutti i precedenti progetti grandiosi. La piramide di Cheope a Giza è la più grande, il Burj Khalifa a Dubai è il più alto, e la Grande Muraglia Cinese è la più lunga.

Tuttavia, organizzare il lavoro su tali progetti è molto difficile. Se costruisci una nuova piramide due volte più alta, richiederà otto volte più pietra. Quindi, devi o aumentare la produttività delle cave di pietra, o aprire più cave.

Dovrai anche trovare otto volte più ingegneri, forse aprire scuole di ingegneria, standardizzare i disegni, la geometria, la scrittura. Insomma, un bel rebus...

Nei migliaia di anni trascorsi dalla costruzione delle piramidi nulla è cambiato — le persone continuano a pensare a come fare sempre più lavoro in meno tempo. E quando sono stati inventati i computer, i migliori cervelli dell'umanità hanno iniziato a lavorare su questo problema.

Come eseguire un programma dieci volte più velocemente? Sembrerebbe una domanda strana — se il processore già lavora alla massima velocità, probabilmente non è possibile. Tuttavia, non ho menzionato a caso i migliori cervelli dell'umanità. Hanno analizzato il lavoro di tutti i programmi e sono giunti alla conclusione che ci sono tre grandi direzioni per crescere.

Eliminazione dei tempi morti

Si scopre che la maggior parte del tempo il programma rimane in attesa. Aspetta costantemente qualcosa: i dati devono essere copiati da un posto della memoria all'altro, caricati dal disco rigido in memoria, si deve aspettare la risposta del server a una richiesta, l'inserimento dati dall'utente ecc.

Tutte queste operazioni non vengono eseguite dal processore centrale, ma dai controller della memoria, del disco ecc. E il processore centrale nel frattempo potrebbe essere utilizzato per qualcosa di utile. Così è nata l'idea di eseguire in un processore non un singolo flusso di esecuzione di comandi (thread), ma diversi.

E mentre, per esempio, un thread aspetta l'inserimento dati dall'utente, il secondo scarica qualcosa dalla rete, il terzo elabora i dati, il quarto disegna immagini sullo schermo. Poi questa idea evolve in compiti asincroni e coroutine, ma ne parleremo più avanti.

Più programmi

Se i programmi rimangono in attesa per l'80% del tempo, questo, ovviamente, non va bene. D'altra parte, non possiamo riscrivere tutti i programmi secondo i nostri nuovi approcci. Forse il problema può essere risolto in un altro modo — possiamo semplicemente eseguire diversi programmi contemporaneamente sul computer.

In questo caso, il sistema operativo monitora il lavoro dei programmi e se un programma è in attesa, passa il suo tempo di esecuzione a un altro programma. Questo cambio avviene decine di volte al secondo, e l'utente non nota i cambiamenti — dal suo punto di vista i programmi si eseguono contemporaneamente.

Più processori

Eseguire i programmi contemporaneamente è figo, ma cosa succede se ci sono molti programmi, e pochi tempi morti? Nessun tempo morto significa nessun uso efficiente. Per esempio, abbiamo dieci programmi che calcolano qualcosa, o un gioco che consuma risorse e qualcos'altro insieme.

La soluzione a questo problema è stata l'aggiunta di più processori nel processore. Per evitare confusione, sono stati chiamati core. Ora abbiamo processori che hanno diversi core (sotto-processori), su cui lavorano parallelamente decine di programmi.

Curiosità! Numero di core nei processori

Al giorno d'oggi, i processori server possono avere da 64 a 256 core, e in alcuni casi specializzati anche di più. Per esempio, i processori AMD EPYC di 4ª generazione offrono fino a 96 core, mentre l'IBM POWER10 può avere fino a 240 core su un chip. Anche i processori per utenti comuni si sono evoluti significativamente: le CPU desktop ad alte prestazioni, come l'AMD Threadripper, possono avere fino a 64 core, mentre i modelli più comuni hanno solitamente da 6 a 16 core.

E dove si va a finire? C'è ancora spazio per crescere! In primo luogo, su una scheda madre server si possono montare più processori, ad esempio due o persino quattro. In secondo luogo, i server possono essere uniti in rack server da 10-20 unità. E i rack server — nei data center, dove ci sono migliaia di rack.

Sistemi distribuiti e architetture a microservizi sono diventati una pratica comune nello sviluppo di software moderno. Molte grandi aziende, come Google, Amazon, Netflix, e persino aziende più piccole, utilizzano sistemi distribuiti per gestire grandi volumi di dati, garantire alta disponibilità e scalabilità dei loro servizi. Questi sistemi permettono di utilizzare efficacemente le risorse di molti server che lavorano insieme come un unico sistema, migliorando notevolmente le prestazioni e la resilienza delle applicazioni.

1.2 Vantaggi

Il multithreading, o esecuzione simultanea di compiti all'interno di un programma, offre diversi vantaggi chiave che possono migliorare significativamente le prestazioni e l'efficienza del software. Vediamo i principali vantaggi del multithreading.

1. Aumento delle prestazioni e della velocità di esecuzione

Esecuzione parallela dei compiti: Il multithreading consente di eseguire più compiti contemporaneamente, cosa particolarmente utile per i programmi che richiedono l'esecuzione di molte operazioni indipendenti. Questo permette di accelerare l'esecuzione del programma, poiché i compiti vengono eseguiti parallelamente, utilizzando tutte le risorse del processore disponibili.

Uso dei processori multicore: I processori moderni hanno diversi core, e il multithreading consente di utilizzarli completamente, distribuendo i thread su diversi core per eseguire i compiti in parallelo.

2. Miglioramento della reattività e interazione con l'utente

Compiti in background: Il multithreading consente di eseguire operazioni lunghe o che consumano risorse in background, mantenendo al contempo il thread principale, responsabile dell'interfaccia utente, reattivo. Questo migliora l'esperienza utente, poiché l'interfaccia non si blocca durante l'esecuzione di compiti pesanti.

Operazioni asincrone: L'interazione con l'utente e la gestione degli eventi possono avvenire parallelamente all'esecuzione dei compiti principali, rendendo le applicazioni più reattive ed efficienti.

3. Uso efficiente delle risorse di sistema

Ottimizzazione delle risorse: Il multithreading consente di utilizzare in modo più efficiente le risorse di sistema, come il tempo del processore e la memoria. Questo è particolarmente importante per i server e i sistemi di calcolo ad alte prestazioni, dove il multithreading consente di gestire un gran numero di richieste e compiti contemporaneamente.

Gestione dell'I/O: Le applicazioni multithreading possono gestire i compiti di input-output (ad esempio, operazioni di rete, lettura e scrittura file) in modo più efficiente, poiché i thread possono eseguire altre operazioni mentre uno di essi è in attesa del completamento di un'operazione di input-output.

4. Supporto al multitasking

Multitasking: Il multithreading consente di eseguire più compiti contemporaneamente all'interno di un solo processo, semplificando lo sviluppo di applicazioni che richiedono il multitasking, come server web, basi di dati e applicazioni in tempo reale.

Elaborazione dati parallela: Nei compiti che coinvolgono l'elaborazione di grandi quantità di dati, il multithreading consente di suddividere i dati in parti e di elaborarli in parallelo, accelerando notevolmente l'esecuzione del compito.

Esempi di utilizzo del multithreading

Server web: Il multithreading consente ai server web di gestire molte richieste client contemporaneamente, aumentando le prestazioni e la scalabilità dei server.

Interfacce grafiche utente (GUI): Nelle applicazioni con interfaccia grafica, il multithreading permette di eseguire calcoli lunghi in background, mantenendo l'interfaccia reattiva.

Calcoli scientifici: Il multithreading è utilizzato per l'elaborazione parallela dei dati nei calcoli scientifici, permettendo di accelerare notevolmente l'esecuzione di compiti computazionali complessi.

Giochi e simulazioni: Nei giochi il multithreading consente di elaborare simultaneamente fisica, grafica, suoni e azioni dell'utente, migliorando le prestazioni e il realismo.

1.3 Nome corretto

C'è una critica al nome "multithreading". È composto da due parole: "multi" e "thread", come per suggerire che all'interno del programma ci sono molti "flussi di esecuzione di comandi" che fanno qualcosa.

Bella analogia, ma nella letteratura inglese (originale) per indicare diverse azioni eseguite in parallelo si usa il termine "thread" (thread). E, di conseguenza, il multithreading si chiama multi-threading.

Questo si potrebbe considerare un piccolo malinteso — poco importa come diversi termini vengono tradotti in un'altra lingua, se non fosse che in programmazione si è iniziato a usare attivamente una cosa chiamata stream, che oltre che con la parola "flusso" non può essere tradotta.

Perciò ora nella terminologia in lingua italiana c'è un po' di confusione, che si risolve in due modi:

  • Thread (filo) viene tradotto come "flusso di esecuzione [di comandi]".
  • Stream (flusso) viene tradotto come "flusso di dati".

D'altra parte, molti programmatori hanno semplicemente iniziato a usare i termini inglesi senza tradurli:

  • Thread (filo) viene pronunciato come "thread", e il multithreading come "multi-threading".
  • Stream (flusso) viene pronunciato come "stream".

Il thread è spesso chiamato filo, ma il termine "multi-filamento" non si è mai affermato. Pertanto, spesso nella conversazione si utilizzano "filo" e "multithreading" contemporaneamente.

L'uso di molti termini presi in prestito arricchisce la lingua, consente di dare nuovi significati alle parole e semplifica la comunicazione con colleghi di altri paesi. Sono completamente a favore di questo approccio.

Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION