Task Manager sta dicendo che il sistema è in esecuzione con oltre un migliaio di thread


16

Ho aperto Task Manager e guardò sotto l'area "Sistema" e vide:

Discussioni: 1337

Dal momento che ho un processore dual-core con hyper-threading disponibile (ovvero quattro thread), come è possibile avere 1000+ thread quando il mio processore dovrebbe avere solo quattro?


3
Non è per questo che lo chiamano iper -threading? :)
a CVn

9
Accidenti, hanno finalmente inventato "multiprogrammazione" ??? (Questo è il 1967, giusto?)
Daniel R Hicks

10
Qualcuno ha appena cambiato il numero per essere il 1337?
Erty Seidohl

11
In che modo un'azienda con quattro sportelli ha 1337 dipendenti? Facile; gli impiegati a turno usando le scrivanie.
Eric Lippert

Risposte:


49

La semplice risposta è che non tutti i thread sono in esecuzione contemporaneamente. Per una spiegazione più completa, continua a leggere.

Il programma di pianificazione delle operazioni del sistema operativo è generalmente pensato per pianificare le applicazioni e, così facendo, consente di eseguire un'attività mentre il computer sta lavorando su un'altra. Ai vecchi tempi, la cartina di tornasole del multitasking stava formattando un floppy disk mentre faceva qualcos'altro. Se si desidera veramente mettere il sistema operativo alla prova, si formattare un disco floppy durante il download di un file su un modem collegato alla porta seriale. Dato che l'hardware è diventato abbastanza potente da farlo davvero in modo significativo, la riproduzione del video a volte è stata inclusa anche in questi test. Se il task scheduler del sistema operativo fosse in grado di gestire senza problemi queste attività, allora potrebbe gestire qualsiasi cosa.

Tuttavia, l'utilità di pianificazione non pianifica realmente le applicazioni (processi), ma pianifica discussioni . Ogni applicazione ha almeno un thread, ma può potenzialmente utilizzare un numero elevato di thread per dividere il lavoro che fa in parti correlate o indipendenti. Ad esempio, è comune che un'applicazione contenga un thread che gestisce l'interfaccia utente e che crei un altro thread quando l'utente avvia un'operazione potenzialmente di lunga durata (che potrebbe essere un'operazione come la stampa, il ricalcolo di un foglio di calcolo, l'esecuzione di un ambiente di sviluppo) una ricerca di simboli, ecc. ecc.). Alcuni ambienti di programmazione introducono una certa quantità di thread invisibili al programmatore; per esempio, Giava e .NETTO potresti fare raccolta dei rifiuti in un thread separato, che è fuori dal controllo immediato del programmatore. Alcuni programmi creano presto un certo numero di thread e li raggruppano, perché la creazione di nuovi thread è un'operazione relativamente costosa (quindi non è necessario creare un thread ogni volta che ne hai bisogno). Tutto ciò che fa un'anteprima viene solitamente eseguito in un thread separato, quindi il resto dell'interfaccia utente rimane reattivo mentre viene generata l'anteprima. E così via. Presi insieme, tutto ciò significa che il numero di thread sul sistema in qualsiasi momento può facilmente essere molte volte il numero di processi.

Ogni thread può essere in uno dei pochi stati possibili, ma la distinzione più importante è tra in esecuzione , eseguibile e in attesa stati; la terminologia può differire leggermente, ma questa è l'idea generale. In qualsiasi momento, solo un thread per virtual (a causa di hyperthreading e tecnologie simili) può essere il core della CPU in esecuzione (cioè, eseguendo le istruzioni del codice macchina), ma qualsiasi numero di thread può essere eseguibile (significa che è un candidato ad ottenere la CPU la prossima volta che lo scheduler deve prendere una decisione su quale thread dovrebbe essere autorizzato a funzionare). In attesa (noto anche come thread bloccato) sono proprio questo, in attesa di qualcosa - i casi più comuni probabilmente sono che è in attesa di utente, disco o I / O di rete (l'input dell'utente, in particolare, è eccezionalmente lento).

Il conteggio dei thread che vedi nel task manager è il numero totale di thread in uno di questi stati. Ad esempio, il sistema Windows 7 su cui sto scrivendo attualmente ha circa 70 processi avviati, ma quasi 900 thread. Con tutti i processi in background per gestire vari compiti e come sono probabilmente suddivisi in una moltitudine di thread ciascuno, questo non è un numero eccessivo.

Andando un po 'più in profondità nell'implementazione tecnica, il fulcro di un programmatore di task del sistema operativo multitasking pre-empiricamente è solitamente un qualche tipo di hook di interrupt hardware. Ciò significa che il kernel può arrestare la CPU quando non ha lavoro utile da eseguire (questo è quasi certamente uno dei motivi, se non il motivo, perché Linux controlla il HLT istruzione all'avvio IA-32 CPU -compatibili, e probabilmente esegue controlli simili su altre architetture), senza la certezza che in alcuni momenti futuri ragionevolmente determinati, un interrupt verrà attivato e l'utilità di pianificazione sarà invocata. Poiché l'interrupt si attiva indipendentemente da quale altro lavoro la CPU sta eseguendo (è l'idea alla base degli interrupt), lo scheduler viene eseguito regolarmente e ottiene la possibilità di determinare quale thread deve essere eseguito durante il seguente intervallo di tempo. Poiché i commutatori di contesto sono relativamente costosi, di solito è possibile (almeno attraverso il codice sorgente) sintonizzare quanto aggressivamente lo schedulatore passa da un thread all'altro; il cambio di thread più spesso fa sì che il sistema diventi più reattivo, ma il sovraccarico di commutazione significa che il tempo complessivo per terminare una determinata serie di attività è più lungo. Il più veloce il sistema sarà uno che passa solo tra i thread quando il thread in esecuzione non è più possibile eseguire (ovvero viene bloccato in attesa di qualcosa, o ha finito il suo lavoro) perché riduce al minimo il sovraccarico, mentre il più reattivo il sistema passerà da un thread all'altro ogni volta che lo scheduler viene richiamato perché riduce al minimo il tempo medio di attesa prima che un particolare thread ottenga il tempo della CPU. L'impostazione ideale di solito è una via di mezzo tra questi due, e il compromesso tra queste scelte è probabilmente uno dei motivi principali per cui Linux offre diversi scheduler tra cui scegliere e alcuni parametri di ottimizzazione attraverso la configurazione del kernel.

D'altro canto, i sistemi operativi e gli ambienti operativi multitasking multitasking ( Windows 3.x essendo un esempio), affidarsi a ciascuna applicazione per cedere regolarmente il controllo allo scheduler. Di solito c'è una funzione API specificatamente pensata per farlo, e spesso molte funzioni API lo fanno come parte del loro flusso di esecuzione interno, perché aiuta a rendere l'esperienza utente più fluida. Questo approccio alla progettazione funziona bene purché tutte le applicazioni siano ben educate e cedano il controllo con brevi intervalli durante qualsiasi operazione di lunga durata (a lungo termine significa più di una piccola frazione di secondo), ma un'applicazione che non può intasare l'intero sistema. Questo è uno dei motivi principali per cui Windows 3.x ha fatto così male nel test multitasking che ho citato sopra, mentre OS / 2 passeggiava allegramente mentre eseguiva gli stessi compiti sullo stesso hardware: un'applicazione poteva dire all'unità disco floppy di scrivere un determinato settore e il tempo necessario per farlo prima che la chiamata fosse effettivamente misurabile (da decine a centinaia di millisecondi o Di Più); un sistema multitasking preventivamente avrebbe il suo scheduler irrompere nella sua prossima chiamata programmata, notare che il thread che è attualmente in esecuzione è effettivamente bloccato dalla chiamata di scrittura e passa semplicemente a un altro thread che è eseguibile. (In pratica è un po 'più coinvolto, ma questa è l'idea generale).

In entrambi gli ambienti di multitasking e cooperazione preventivamente, esiste anche la possibilità che diversi thread abbiano priorità diverse. Ad esempio, è probabilmente più importante eseguire in modo tempestivo il thread che sta ricevendo i dati su un collegamento di comunicazione rispetto a quello che aggiorna la visualizzazione dell'ora di sistema, quindi il thread ricevente ha priorità alta e il thread di aggiornamento della visualizzazione del tempo ha bassa priorità . Le priorità dei thread hanno un ruolo nella decisione dello scheduler su quale thread consentire di eseguire (ad esempio, molto semplificato i thread con priorità alta devono sempre essere eseguiti prima dei thread a bassa priorità, quindi, anche se il thread con priorità bassa ha del lavoro da svolgere, se il thread ad alta priorità diventa eseguibile ha la precedenza), ma tali decisioni di pianificazione specifiche non influiscono sulla progettazione del meccanismo sottostante.


11
Amo "l'input dell'utente in particolare è eccezionalmente lento"
John Dvorak

I "fili" che una CPU "ha" si riferisce al numero che può eseguire simultaneamente in un dato momento. Passa tra i thread attivi, assegnando a ciascuno un turno o una parte della CPU per un intervallo di tempo, quando possibile. I processi / thread "bloccati" o in attesa di I / O (come disco, input da tastiera / mouse, ecc.) O qualcos'altro (come primitive di sincronizzazione come mutex, ecc.) Saltano il loro turno.
LawrenceC

1
I commenti sono utili per chiedere chiarimenti, ma non sono adatti per discussioni estese, e ad un certo punto diventano difficili da leggere. Puoi per favore portarlo a Super User Chat anziché? Grazie.
slhck

1
@slhck Ho creato una stanza, ma non ho trovato alcun modo per migrare la discussione in questi commenti, il che sarebbe bello. È qualcosa che puoi fare manualmente come moderatore? chat.stackexchange.com/rooms/9547/...
a CVn

1
Sfortunatamente no. Esiste un processo di migrazione automatico che non può essere attivato manualmente, ma non possiamo spostare commenti in una chat room. Lasciamo che i commenti qui rimangano per il momento, ma incoraggerei gli altri a seguire la discussione nella chat room che hai creato.
slhck

19

Pensa a un'autostrada a quattro corsie con 1037 veicoli.

Il tuo sistema operativo ha bisogno di un sacco di processi in esecuzione per lavorare su molti servizi. Anche i più semplici programmi grafici richiedono la programmazione multithread. Quando pensi ai tuoi molti programmi aperti, vedi che c'è bisogno di condividere le risorse di calcolo.

Ciò che mostra il tuo task manager è il carico del sistema corrente. Quello che mostrano le specifiche della tua comp è il numero di thread (in frontend) accettati per l'esecuzione parallela. Senza entrare molto nella differenza tra le funzioni di hyperthreading e multicore, con un thread logico più accettabile, un sistema generalmente funzionerà meglio.


8
"Anche i più semplici programmi grafici richiedono una programmazione multithread." Sbagliato. È perfettamente possibile scrivere applicazioni GUI a thread singolo; fino a Windows 95, a tutti gli effetti tutti lo facevano in quel modo. Rende le attività più complicate (ad esempio, la stampa in background è banale con più thread ma decisamente non banale in una singola applicazione con thread, in particolare se anche la memoria è vincolata come allora), ma c'è un'enorme differenza tra " X è reso più facile da Y "e" X richiede Y ".
a CVn

8
@ MichaelKjling: "fino a Windows 95, a tutti gli effetti tutti lo facevano in quel modo" * - davvero? Anche sui sistemi * nix che eseguono Motif negli anni '80?
LarsH

@LarsH Un buon punto, e uno che ho pensato troppo tardi per modificare il commento. Ma questo non nega il punto: vale a dire che è perfettamente possibile scrivere applicazioni GUI a thread singolo. Non è necessario il multithreading per questo, anche se rende alcune attività (considerevolmente) più facili sul programmatore.
a CVn

@ MichaelKjling: Sono d'accordo, non nega il tuo punto, che è valido. (Non penso che l'affermazione errata di uprego neghi il suo punto sia.)
LarsH

Come esempio di ciò che ha detto @ MichaelKjörling, Visual Basic (prima di .NET) come linguaggio di programmazione no supporto multi-threading. Qualunque cosa è stato eseguito su un singolo thread. Se si desidera elaborare l'input dell'utente nel mezzo di un'operazione di lunga durata, si dovrebbe chiamare DoEvents, che processerebbe la coda dei messaggi, ma ciò avveniva sullo stesso thread e bloccava quell'operazione a lungo termine fino a quando tutti i messaggi non venivano elaborati. (Naturalmente, puoi chiamare le funzioni API di Win32 e / o creare processi aggiuntivi, ma a quel punto potresti anche usare uno dei linguaggi di livello inferiore.)
Bob

5

Dovremmo fare un passo indietro e chiederci: come può un computer con una singola CPU avere due thread?

I thread sono entità software, non hardware. Per avere un altro thread, hai solo bisogno di memoria per gli oggetti che compongono il thread, come una struttura descrittiva e uno stack.

Il sistema operativo cambia tra i thread in momenti diversi, come all'interno di alcuni interrupt (come un interrupt del timer) o quando i thread effettuano chiamate nel sistema operativo.

Di tutti i thread che esistono nel sistema, solo un sottoinsieme di solito si trova in uno stato che viene comunemente chiamato "eseguibile". I thread eseguibili sono desiderosi di essere eseguiti: sono in esecuzione o seduti in una "coda di esecuzione", in attesa di essere inviati dallo scheduler. I thread che non sono eseguibili sono "bloccati", in attesa di acquisire qualche risorsa o ricevere input, o "dormendo" che è come essere bloccati su input, dove "input" è il passare del tempo. Un "cambio di contesto" ha luogo quando la funzione scheduler nel sistema operativo dà un'occhiata alla coda di esecuzione di un processore e sceglie un thread diverso da eseguire.

Non essere confuso da "Hyperthreading" , che è il nome di Intel per una particolare funzionalità hardware.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.