Qual è la differenza tra un singolo thread e più thread?

Migliore risposta

La risposta alla domanda posta è: è la stessa della differenza tra “uno “e” molti “.

Ma penso che quello che probabilmente intendevi davvero è qualcosa di più simile a questo: in che modo le metodologie di programmazione differiscono per la programmazione in un singolo thread in un singolo processo rispetto a più thread in un singolo processo?

Sono stati scritti libri sullargomento. Ma molto brevemente, le differenze riguardano tutte un fattore: quando si programma in un singolo thread e processo, si sa sempre come si è arrivati ​​allistruzione corrente. Le istruzioni si verificano in una singola sequenza. Ma quando si programma per molti thread, non si ha idea di quali istruzioni siano state eseguite in quale ordine per arrivare allistruzione corrente. Questo rende la programmazione più complicata.

Ma cè un altro fattore che la complica: a differenza dei processi, i thread condividono la memoria. Non sai quale thread ha toccato per ultimo una determinata posizione di memoria, o quale sarà il prossimo, a meno che tu non abbia una sorta di “sincronizzazione”. Da qui la parola chiave “synchronized” in Java (strappata da Ada). Monitor, semafori, lock , le variabili di condizione e persino il passaggio di messaggi sono stati tutti utilizzati per la sincronizzazione.

Risposta

(Aggiornamento: fai attenzione a unaltra risposta che dice che non puoi avere un server web a thread singolo che gestisce bene le richieste simultanee perché semplicemente non è vero.)

Perché un server web multithread è migliore di un server a thread singolo? Non lo è.

Ci sono quattro modi di base in cui un server web può gestire la concorrenza:

  1. fork un processo del sistema operativo per richiesta (come le vecchie versioni di Apache)
  2. generare un thread del sistema operativo per richiesta (come una nuova versione di Apache)
  3. utilizzando un ciclo di eventi a thread singolo (come nginx )
  4. utilizzando fili verdi o processi leggeri pianificato da un runtime VM invece che dal sistema operativo (come in Erlang)

Attualmente gli approcci più comuni sono il numero 2 e 3.

Ci sono pro e contro di entrambi di loro. Per le operazioni I / O-bound (una caratteristica di un tipico server web) ottieni prestazioni migliori e maggior numero di richieste simultanee quando utilizzi un loop di eventi a thread singolo . Ma lo svantaggio è che devi utilizzare esclusivamente I / O asincrono non bloccante per tutte le operazioni, altrimenti bloccherai il loop degli eventi e perderai le prestazioni. Per questo motivo è più facile implementare un server multi-threaded ma paghi in termini di prestazioni.

Per le operazioni legate alla CPU (meno comune per un normale server web, forse più comune per unAPI ad alta intensità di calcolo) è meglio avere un thread del sistema operativo o un processo per core . È facile da fare con i loop di eventi a thread singolo perché puoi eseguire un cluster di più processi uno per core. È difficile da fare con i server multi-thread perché se la generazione di thread è lunico modo per gestire le richieste simultanee, allora non puoi davvero controllare quanti thread avrai, poiché non controlli il numero di richieste. Una volta che hai più thread rispetto al numero di core della CPU, perdi le prestazioni per i cambi di contesto e usi anche molta RAM.

Questo è il motivo per cui un server nginx a thread singolo funziona meglio di un server Web Apache multi-thread (ed è per questo che nginx è stato creato in primo luogo). Inoltre Redis , un database noto per prestazioni eccezionalmente elevate è a thread singolo .

Un esempio reale che posso darti è questo: il mio primo server web era Apache in esecuzione su una macchina Linux con 500 MB di RAM. Ha biforcato un nuovo processo per ogni richiesta (in realtà aveva un pool, quindi non cera molto fork coinvolto, ma doveva mantenere in vita quei processi per riutilizzarli e ucciderli di tanto in tanto per evitare perdite di risorse).

Il mio sistema operativo utilizzava circa 100 MB di RAM. Ogni processo Apache utilizzava 20 MB di RAM. Significava che il mio server poteva gestire solo 20 richieste simultanee e non cera modo di aggirarlo perché non avevo più RAM. I processi erano per lo più bloccati su I / O quindi lutilizzo della CPU era molto basso, ogni richiesta superiore a quelle 20 doveva aspettare e se quelle 20 erano ad es download di lunga durata quindi il mio server non rispondeva completamente.

Quando è stato introdotto il server web nginx, utilizzava un ciclo di eventi a thread singolo e non si bloccava per nessuna richiesta. Potrebbe gestire molte più richieste simultanee, non avendo problemi con il mitico problema c10k: nginx è stato fondamentalmente creato per risolvere il problema c10k (10.000 richieste simultanee).

Immagina quanta RAM viene sprecata per 10.000 thread se tu potrebbe persino generarne così tante e quanto tempo viene utilizzato per i cambi di contesto.

Utilizzo della memoria di Apache multi-thread rispetto a nginx a thread singolo:

Per inciso, questo è il motivo per cui Ryan Dahl ha utilizzato un I / O non bloccante e un loop di eventi a thread singolo in Node.js e usa ancora la stessa idea in Deno, perché questo è il modo per scrivere server di rete ad alte prestazioni (contrariamente a quanto potresti leggere in altre risposte qui).

Lascia un commento

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