Multithreading: qual è il punto di più thread rispetto ai core?


142

Ho pensato che il punto di un computer multi-core fosse che poteva eseguire più thread contemporaneamente. In tal caso, se hai una macchina quad-core, qual è il punto di avere più di 4 thread in esecuzione alla volta? Non si sarebbero semplicemente rubati del tempo (risorse CPU) l'uno dall'altro?


52
godiamo di questo tipo di domande, mettono in dubbio il fondamentale di qualcosa, che è dato per scontato ... continua a venire ..
Srinivas Reddy Thatiparthy,

6
Quando è stata l'ultima volta che Firefox, MS Word, Winamp, Eclipse e un gestore di download (più di quattro programmi / processi) sono stati eseguiti contemporaneamente sul tuo computer quad core? Inoltre, a volte una singola applicazione può generare più di quattro thread. Che ne dici?
Amarghosh,

1
Rubare non è necessariamente male. Potresti avere un thread con una priorità più alta per attività importanti che devono rubare tempo.
Kichik

1
@Amarghosh Immagino che fosse la domanda, perché una singola applicazione potrebbe voler generare più thread che core se non sembra portare alcun vantaggio in termini di prestazioni. E il tuo esempio con più di quattro programmi non è abbastanza rilevante qui. Come hai giustamente notato, questi sono processi. La funzionalità multitasking del sistema operativo (multiplexing di processo) ha ben poco a che fare con i thread all'interno di un processo.
Aleksandr Ivannikov,

Risposte:


81

La risposta ruota attorno allo scopo dei thread, che è il parallelismo: eseguire diverse linee separate di esecuzione contemporaneamente. In un sistema 'ideale', avresti un thread in esecuzione per core: nessuna interruzione. In realtà non è così. Anche se hai quattro core e quattro thread di lavoro, il tuo processo e i thread verranno costantemente scambiati per altri processi e thread. Se stai eseguendo un sistema operativo moderno, ogni processo ha almeno un thread e molti ne hanno di più. Tutti questi processi sono in esecuzione contemporaneamente. Probabilmente hai centinaia di thread in esecuzione sul tuo computer in questo momento. Non avrai mai una situazione in cui un thread viene eseguito senza che il tempo venga "rubato" da esso. (Beh, potresti farlo se funziona in tempo reale, se si utilizza un sistema operativo in tempo reale o, anche su Windows, utilizzare una priorità di thread in tempo reale. Ma è raro.)

Con questo come sfondo, la risposta: Sì, più di quattro thread su una vera macchina a quattro core possono darti una situazione in cui "rubano tempo gli uni agli altri", ma solo se ogni singolo thread ha bisogno del 100% di CPU . Se un thread non funziona al 100% (come potrebbe non essere un thread dell'interfaccia utente o un thread che sta eseguendo una piccola quantità di lavoro o in attesa di qualcos'altro), un altro thread in fase di pianificazione è in realtà una buona situazione.

In realtà è più complicato di così:

  • E se avessi cinque pezzi di lavoro che tutti devono essere eseguiti contemporaneamente? Ha più senso eseguirle tutte in una volta, piuttosto che eseguirle quattro e poi eseguire la quinta in seguito.

  • È raro che un thread abbia realmente bisogno del 100% di CPU. Nel momento in cui utilizza l'I / O del disco o della rete, ad esempio, potrebbe passare del tempo in attesa di fare nulla di utile. Questa è una situazione molto comune.

  • Se hai del lavoro che deve essere eseguito, un meccanismo comune è usare un threadpool. Potrebbe sembrare sensato avere lo stesso numero di thread dei core, ma il pool di thread .Net ha fino a 250 thread disponibili per processore . Non sono sicuro del motivo per cui lo fanno, ma la mia ipotesi è che abbia a che fare con la dimensione delle attività che vengono assegnate per l'esecuzione sui thread.

Quindi: rubare il tempo non è una brutta cosa (e non è nemmeno un vero furto: è come dovrebbe funzionare il sistema.) Scrivi i tuoi programmi multithread in base al tipo di lavoro che faranno i thread, che potrebbe non essere CPU -limite. Scopri il numero di thread necessari in base alla profilazione e alla misurazione. Potresti trovare più utile pensare in termini di attività o lavori, piuttosto che thread: scrivere oggetti di lavoro e assegnarli a un pool da eseguire. Infine, a meno che il tuo programma non sia veramente critico per le prestazioni, non preoccuparti troppo :)


17
+1 per "ma solo se ogni singolo thread ha bisogno del 100% di CPU". Questo era il presupposto che non avevo realizzato che stavo facendo.
Nick Heiner,

1
Una risposta meravigliosa a una grande domanda. Grazie!
Edgecase,

53

Solo perché esiste un thread non significa sempre che è in esecuzione attivamente. Molte applicazioni di thread coinvolgono alcuni thread che vanno in modalità di sospensione fino a quando non è il momento per loro di fare qualcosa, ad esempio l'input dell'utente che attiva i thread per riattivarsi, eseguire alcune elaborazioni e tornare in modalità di sospensione.

In sostanza, i thread sono attività individuali che possono operare indipendentemente l'una dall'altra, senza che sia necessario essere consapevoli dell'avanzamento di un'altra attività. È del tutto possibile avere più di questi di quanto tu abbia la capacità di correre contemporaneamente; sono ancora utili per comodità anche se a volte devono aspettare in fila uno dietro l'altro.


12
Ben detto. L'argomento "un thread per CPU" si applica solo al codice associato alla CPU. La programmazione asincrona è un altro motivo per usare i thread.
Joshua Davis,

26

Il punto è che, nonostante non si ottenga una vera accelerazione quando il conteggio dei thread supera il conteggio dei core, è possibile utilizzare i thread per districare pezzi di logica che non dovrebbero essere interdipendenti.

Anche in un'applicazione moderatamente complessa, usando un singolo thread prova a fare tutto in modo rapido facendo hash del 'flusso' del tuo codice. Il singolo thread trascorre la maggior parte del tempo a scrutarlo, verificandolo, chiamando condizionalmente le routine in base alle esigenze e diventa difficile vedere altro che una massa di minuzie.

Contrastalo con il caso in cui puoi dedicare thread alle attività in modo tale che, guardando ogni singolo thread, puoi vedere cosa sta facendo quel thread. Ad esempio, un thread potrebbe bloccare l'attesa dell'input da un socket, analizzare il flusso in messaggi, filtrare i messaggi e quando arriva un messaggio valido, passarlo a un altro thread di lavoro. Il thread di lavoro può lavorare su input da diverse altre fonti. Il codice per ognuno di questi mostrerà un flusso pulito e mirato, senza dover effettuare controlli espliciti che non c'è altro da fare.

Partizionare il lavoro in questo modo consente alla tua applicazione di fare affidamento sul sistema operativo per pianificare cosa fare successivamente con la cpu, quindi non devi effettuare controlli condizionali espliciti ovunque nell'applicazione su cosa potrebbe bloccare e cosa è pronto per l'elaborazione.


1
Questo è un pensiero interessante ... Ho sempre sentito che il multithreading di un'app è un'aggiunta netta di complessità, ma ciò che stai dicendo ha senso.
Nick Heiner,

Il multithreading di un'app aggiunge complessità se le sue preoccupazioni non sono adeguatamente separate. Se è progettato con una minima sovrapposizione di preoccupazioni (e quindi stato condiviso) è un netto risparmio in termini di complessità.
SOLO IL MIO OPINIONE corretta il

Esistono modi per strutturare le applicazioni a thread singolo in modo che il flusso di controllo sia più chiaro a livello di scrittura dei programmi. OTOH, se riesci a strutturare i tuoi thread in modo che si scambino messaggi solo tra di loro (invece di avere risorse condivise), è abbastanza semplice capire cosa sta succedendo e far funzionare tutto.
Donal Fellows,

1
Dovrebbe sottolineare, tuttavia, che l'uso dei thread può solo semplificare le cose fino a un certo punto. Troppo spesso viene fatto il tentativo di fare in modo che due thread eseguano il lavoro che dovrebbe essere giustamente svolto da uno, a cui la complessità ritorna a picco. I sintomi sono eccessivi bisogni di comunicazione e sincronizzazione al fine di coordinare i risultati desiderati.
JustJeff,

15

Se un thread è in attesa di una risorsa (come caricare un valore dalla RAM in un registro, I / O del disco, accesso alla rete, avviare un nuovo processo, interrogare un database o attendere l'input dell'utente), il processore può lavorare su un thread diverso e tornare al primo thread una volta che la risorsa è disponibile. Ciò riduce il tempo di inattività della CPU, poiché la CPU può eseguire milioni di operazioni invece di rimanere inattiva.

Considera un thread che deve leggere i dati da un disco rigido. Nel 2014, un tipico core del processore funziona a 2,5 GHz e potrebbe essere in grado di eseguire 4 istruzioni per ciclo. Con un tempo di ciclo di 0,4 ns, il processore può eseguire 10 istruzioni per nanosecondo. Con tempi di ricerca tipici del disco rigido meccanico di circa 10 millisecondi, il processore è in grado di eseguire 100 milioni di istruzioni nel tempo necessario per leggere un valore dal disco rigido. Potrebbero esserci significativi miglioramenti delle prestazioni con dischi rigidi con una piccola cache (buffer da 4 MB) e unità ibride con pochi GB di spazio di archiviazione, poiché la latenza dei dati per letture sequenziali o letture dalla sezione ibrida può essere più veloce di diversi ordini di grandezza.

Un core del processore può passare da un thread all'altro (il costo per mettere in pausa e riprendere un thread è di circa 100 cicli di clock) mentre il primo thread attende un input ad alta latenza (qualcosa di più costoso dei registri (1 clock) e della RAM (5 nanosecondi)) I / O su disco, accesso alla rete (latenza di 250 ms), lettura dei dati da un CD o da un bus lento o da una chiamata al database. Avere più thread che core significa che è possibile svolgere un lavoro utile mentre vengono risolte attività ad alta latenza.

La CPU ha un programmatore di thread che assegna la priorità a ciascun thread e consente a un thread di essere sospeso, quindi riprendersi dopo un tempo prestabilito. È compito del programmatore di thread ridurre il thrashing, che si verificherebbe se ogni thread eseguisse solo 100 istruzioni prima di essere messo nuovamente in sospensione. Il sovraccarico di passare da un thread all'altro ridurrebbe il throughput utile totale del core del processore.

Per questo motivo, potresti voler suddividere il problema in un numero ragionevole di thread. Se si scrivesse codice per eseguire la moltiplicazione della matrice, la creazione di un thread per cella nella matrice di output potrebbe essere eccessiva, mentre un thread per riga o per n righe nella matrice di output potrebbe ridurre i costi generali di creazione, pausa e ripresa dei thread.

Questo è anche il motivo per cui la previsione delle filiali è importante. Se si dispone di un'istruzione if che richiede il caricamento di un valore dalla RAM ma il corpo delle istruzioni if ​​e else utilizza valori già caricati nei registri, il processore può eseguire uno o entrambi i rami prima che la condizione sia stata valutata. Una volta ripristinata la condizione, il processore applicherà il risultato del ramo corrispondente e scarterà l'altro. Eseguire un lavoro potenzialmente inutile qui è probabilmente meglio che passare a un thread diverso, che potrebbe portare a un thrashing.

Dal momento che ci siamo spostati dai processori single-core ad alta velocità di clock ai processori multi-core, la progettazione dei chip si è concentrata sulla stipatura di più core per die, sul miglioramento della condivisione delle risorse on-chip tra i core, sui migliori algoritmi di previsione dei rami, su un overhead di commutazione dei thread migliore, e una migliore pianificazione dei thread.


lo stesso può essere fatto con un singolo thread e una coda: \ c'è davvero qualche vantaggio nell'avere 80 thread su 2-4 core, oltre ad avere solo 2-4 core che consumano attività da una coda non appena arrivano e non hanno niente da fare?
Dmitry,

8

La maggior parte delle risposte sopra parla di prestazioni e operazioni simultanee. Ho intenzione di approcciarlo da una prospettiva diversa.

Prendiamo il caso, diciamo, di un semplicistico programma di emulazione terminale. Devi fare le seguenti cose:

  • cercare i caratteri in arrivo dal sistema remoto e visualizzarli
  • guarda le cose che arrivano dalla tastiera e inviale al sistema remoto

(Gli emulatori di terminali reali fanno di più, incluso potenzialmente l'eco delle cose digitate anche sul display, ma per ora lo passeremo sopra.)

Ora il ciclo per la lettura dal telecomando è semplice, secondo il seguente pseudocodice:

while get-character-from-remote:
    print-to-screen character

Anche il loop per il monitoraggio della tastiera e l'invio è semplice:

while get-character-from-keyboard:
    send-to-remote character

Il problema, tuttavia, è che devi farlo simultaneamente. Il codice ora deve apparire più simile a questo se non hai thread:

loop:
    check-for-remote-character
    if remote-character-is-ready:
        print-to-screen character
    check-for-keyboard-entry
    if keyboard-is-ready:
        send-to-remote character

La logica, anche in questo esempio deliberatamente semplificato che non tiene conto della complessità delle comunicazioni nel mondo reale, è piuttosto offuscata. Con il threading, tuttavia, anche su un singolo core, i due loop pseudocodici possono esistere indipendentemente senza intrecciare la loro logica. Poiché entrambi i thread saranno per lo più associati a I / O, non caricano molto la CPU, anche se, a rigore, sono più dispendiosi di risorse della CPU rispetto al loop integrato.

Ora, ovviamente, l'uso nel mondo reale è più complicato di quanto sopra. Ma la complessità del ciclo integrato aumenta esponenzialmente man mano che si aggiungono ulteriori preoccupazioni all'applicazione. La logica diventa sempre più frammentata e devi iniziare a usare tecniche come macchine a stati, coroutine, ecc. Per rendere le cose gestibili. Gestibile, ma non leggibile. Il threading rende il codice più leggibile.

Quindi perché non dovresti usare il threading?

Bene, se le tue attività sono associate alla CPU anziché agli I / O, il threading rallenta effettivamente il tuo sistema. Le prestazioni ne risentiranno. Molto, in molti casi. ("Thrashing" è un problema comune se si rilasciano troppi thread associati alla CPU. Si finisce per passare più tempo a modificare i thread attivi rispetto a quando si esegue il contenuto dei thread stessi.) Inoltre, uno dei motivi per cui la logica sopra è così semplice è che ho scelto molto deliberatamente un esempio semplicistico (e non realistico). Se volevi fare eco a ciò che è stato digitato sullo schermo, hai un nuovo mondo di sofferenza mentre introduci il blocco delle risorse condivise. Con una sola risorsa condivisa questo non è tanto un problema, ma inizia a diventare un problema sempre più grande poiché hai più risorse da condividere.

Quindi, alla fine, il threading riguarda molte cose. Ad esempio, si tratta di rendere i processi associati agli I / O più reattivi (anche se complessivamente meno efficienti) come alcuni hanno già detto. Si tratta anche di rendere la logica più facile da seguire (ma solo se si minimizza lo stato condiviso). Si tratta di molte cose e devi decidere se i suoi vantaggi superano i suoi svantaggi caso per caso.


6

Anche se puoi sicuramente usare i thread per velocizzare i calcoli a seconda del tuo hardware, uno dei loro usi principali è quello di fare più di una cosa alla volta per motivi di facilità d'uso.

Ad esempio, se è necessario eseguire alcune elaborazioni in background e rimanere sensibili all'input dell'interfaccia utente, è possibile utilizzare i thread. Senza thread, l'interfaccia utente si bloccherebbe ogni volta che si tenta di eseguire elaborazioni pesanti.

Vedi anche questa domanda correlata: usi pratici per i thread


La gestione dell'interfaccia utente è un classico esempio di un'attività associata a IO. Non è utile disporre di un singolo core della CPU che esegua sia attività di elaborazione che IO.
Donal Fellows,

6

Non sono assolutamente d'accordo con l'affermazione di @ kyoryu secondo cui il numero ideale è un thread per CPU.

Pensaci in questo modo: perché abbiamo sistemi operativi multi-elaborazione? Per la maggior parte della storia del computer, quasi tutti i computer avevano una CPU. Eppure dagli anni '60 in poi, tutti i computer "reali" avevano sistemi operativi multi-elaborazione (aka multi-tasking).

Esegui più programmi in modo che uno possa essere eseguito mentre altri sono bloccati per cose come IO.

lascia da parte gli argomenti sul fatto che le versioni di Windows prima di NT fossero multi-tasking. Da allora, ogni vero sistema operativo ha avuto il multi-tasking. Alcuni non lo espongono agli utenti, ma è comunque lì, facendo cose come ascoltare la radio del cellulare, parlare con il chip GPS, accettare l'input del mouse, ecc.

Le discussioni sono solo attività un po 'più efficienti. Non esiste alcuna differenza fondamentale tra un'attività, un processo e un thread.

Una CPU è una cosa terribile da perdere, quindi hai un sacco di cose pronte per usarla quando puoi.

Concordo sul fatto che con la maggior parte dei linguaggi procedurali, C, C ++, Java ecc., Scrivere un codice thread-safe adeguato richiede molto lavoro. Con 6 CPU core oggi sul mercato e 16 CPU core non molto lontane, mi aspetto che le persone si allontanino da questi vecchi linguaggi, poiché il multi-threading è sempre più un requisito fondamentale.

Il disaccordo con @kyoryu è solo IMHO, il resto è fatto.


5
Se hai molti thread associati al processore , il numero ideale è uno per CPU (o forse uno in meno, per lasciarne uno per gestire tutto l'I / O e il sistema operativo e tutto il resto). Se hai thread IO -bound, puoi impilare abbastanza su una singola CPU. App diverse hanno diversi mix di attività associate al processore e associate all'IO; è del tutto naturale, ma perché devi stare attento con le dichiarazioni universali.
Donal Fellows,

1
Naturalmente, la differenza più importante tra thread e processi è che su Windows non c'è fork (), quindi la creazione di processi è davvero costosa, portando a un uso eccessivo di thread.
ninjalj,

Fatta eccezione per il ripiegamento delle proteine, il SETI, ecc., Non esistono attività pratiche per l'utente che sono legate per molto tempo al calcolo. C'è sempre la necessità di ottenere informazioni dall'utente, parlare con il disco, parlare con il DBMS, ecc. Sì, la spesa di fork () è una delle tante cose che Cutler ha maledetto NT con gli altri di DEC.
fishtoprecords,

5

Immagina un server Web che deve soddisfare un numero arbitrario di richieste. È necessario servire le richieste in parallelo perché altrimenti ogni nuova richiesta deve attendere il completamento di tutte le altre richieste (incluso l'invio della risposta su Internet). In questo caso, la maggior parte dei server Web ha un numero di core molto inferiore rispetto al numero di richieste che di solito servono.

Inoltre semplifica lo sviluppatore del server: devi solo scrivere un programma thread che serve una richiesta, non devi pensare di archiviare più richieste, l'ordine in cui le hai servite e così via.


2
Stai scrivendo software per un sistema operativo che supporta il threading ma non ha capacità di multiplexing io? Penso che il web server sia probabilmente un cattivo esempio dato che in questo caso il multiplexing di io sarà quasi sempre più efficiente della generazione di più thread rispetto ai core.
Jason Coco,

3

Molti thread si addormenteranno, in attesa di input dell'utente, I / O e altri eventi.


Di sicuro. basta usare Task Manager su Windows o TOP su un vero sistema operativo e vedere quante attività / processi sono già in sospeso. È sempre il 90% o più.
fishtoprecords,

2

I thread possono aiutare con la reattività nelle applicazioni dell'interfaccia utente. Inoltre, puoi utilizzare i thread per ottenere più lavoro dai tuoi core. Ad esempio, su un singolo core, è possibile avere un thread che esegue IO e un altro che esegue un calcolo. Se fosse a thread singolo, il core potrebbe essenzialmente essere inattivo in attesa del completamento dell'IO. Questo è un esempio di livello piuttosto elevato, ma i thread possono sicuramente essere usati per battere la tua CPU un po 'più difficile.


Più specificamente, un thread può essere in attesa su I / O mentre un altro esegue il calcolo. Se l'I / O impiegasse cicli (significativi) della CPU, non ci sarebbe alcun vantaggio nell'eseguirlo in un thread separato. Il vantaggio è che il tuo thread di calcolo può essere eseguito mentre il tuo thread I / O fa schioccare i pollici aspettando che un grosso cilindro di alluminio ruoti in posizione, o che i pacchetti arrivino sul cavo dall'Islanda o altro.
Ken,

2

Un processore, o CPU, è il chip fisico che è collegato al sistema. Un processore può avere più core (un core è la parte del chip in grado di eseguire le istruzioni). Un core può apparire al sistema operativo come processori virtuali multipli se è in grado di eseguire simultaneamente più thread (un thread è una singola sequenza di istruzioni).

Un processo è un altro nome per un'applicazione. In generale, i processi sono indipendenti l'uno dall'altro. Se un processo muore, non provoca anche la morte di un altro processo. È possibile che i processi comunichino o condividano risorse come memoria o I / O.

Ogni processo ha uno spazio e uno stack di indirizzi separati. Un processo può contenere più thread, ognuno in grado di eseguire istruzioni contemporaneamente. Tutti i thread in un processo condividono lo stesso spazio indirizzo, ma ogni thread avrà il proprio stack.

Spero che con queste definizioni e ulteriori ricerche usando questi fondamenti ti aiuterà a capire.


2
Non vedo come questo risolva la sua domanda. La mia interpretazione della sua domanda riguarda l'uso dei thread dei core e l'uso ottimale delle risorse disponibili, o il comportamento dei thread quando si aumenta il loro numero, o qualcosa del genere comunque.
David,

@ David forse non era una risposta diretta alla mia domanda, ma sento ancora di aver imparato leggendolo.
Nick Heiner,

1

L'uso ideale dei thread è, in effetti, uno per core.

Tuttavia, a meno che non utilizzi esclusivamente IO asincroni / non bloccanti, ci sono buone probabilità che ad un certo punto avrai dei thread bloccati su IO, che non utilizzeranno la tua CPU.

Inoltre, i linguaggi di programmazione tipici rendono in qualche modo difficile utilizzare 1 thread per CPU. I linguaggi progettati in base alla concorrenza (come Erlang) possono semplificare l'uso di thread extra.


L'uso dei thread per le attività periodiche è un flusso di lavoro molto comune e gradito, e sarebbe molto meno che ideale se rubassero un nucleo.
Nick Bastin,

@Nick Bastin: Sì, ma è più efficiente incollare tali attività in una coda di attività ed eseguirle da quella coda (o una strategia simile). Per un'efficienza ottimale, 1 thread per core batte tutto, poiché impedisce al sovraccarico di passare da un contesto all'altro non necessario e di allocare stack aggiuntivi. Indipendentemente da ciò, l'attività periodica deve rubare un core mentre è "attiva", poiché la CPU può effettivamente eseguire solo un'attività per core (oltre a cose come l'hyperthreading se disponibile).
Kyoryu,

@Nick Bastin: Sfortunatamente, come ho detto nella risposta principale, la maggior parte delle lingue moderne non si prestano bene all'implementazione di un sistema che lo fa in modo efficace non è banale - finisci per fare un po 'di lotta contro l'uso tipico della lingua.
Kyoryu,

Il mio punto non è che un thread per core non sia ottimale, è che un thread per core è un sogno irrealizzabile (a meno che tu non sia incorporato) e progettare per provare a colpirlo è una perdita di tempo, quindi potresti anche fai ciò che ti semplifica (e non è comunque meno efficiente su un moderno scheduler), piuttosto che cercare di ottimizzare il numero di thread che stai utilizzando. Dovremmo girare i fili senza una buona ragione? Certo che no, ma se stai sprecando inutilmente risorse del computer è una preoccupazione indipendentemente dal thread.
Nick Bastin

@Nick Bastin: Quindi, per riassumere, un thread per core è l'ideale, ma in realtà non è molto probabile raggiungerlo. Probabilmente avrei dovuto essere più forte di "un po 'difficile" quando ho parlato della probabilità che si ottenga effettivamente una cosa del genere.
Kyoryu,

1

Il modo in cui alcune API sono progettate, non hai altra scelta che eseguirle in un thread separato (qualsiasi cosa con operazioni di blocco). Un esempio potrebbero essere le librerie HTTP di Python (AFAIK).

Di solito questo non è un grosso problema (se si tratta di un problema, il sistema operativo o l'API devono essere forniti con una modalità operativa asincrona alternativa, ovvero:) select(2), perché probabilmente significa che il thread verrà sospeso durante l'attesa di I / O completamento. D'altra parte, se qualcosa sta facendo un pesante calcolo, è necessario metterlo in un thread separato che dire, il filo GUI (a meno che non vi piace multiplexing manuale).


1

So che questa è una domanda super vecchia con molte buone risposte, ma sono qui per sottolineare qualcosa che è importante nell'ambiente attuale:

Se si desidera progettare un'applicazione per il multi-threading, non si dovrebbe progettare per un'impostazione hardware specifica. La tecnologia della CPU sta avanzando abbastanza rapidamente da anni e il numero di core sta aumentando costantemente. Se si progetta deliberatamente l'applicazione in modo tale che utilizzi solo 4 thread, si sta potenzialmente limitando un sistema octa-core (ad esempio). Ora, anche i sistemi a 20 core sono disponibili in commercio, quindi un tale progetto sta sicuramente facendo più danni che benefici.


0

In risposta alla tua prima congettura: le macchine multi-core possono eseguire simultaneamente più processi, non solo i thread multipli di un singolo processo.

In risposta alla tua prima domanda: il punto di più thread è di solito eseguire simultaneamente più attività all'interno di una sola applicazione. I classici esempi in rete sono un programma di posta elettronica che invia e riceve posta e un server Web che riceve e invia richieste di pagine. (Si noti che è essenzialmente impossibile ridurre un sistema come Windows all'esecuzione di un solo thread o anche solo di un processo. Eseguire il Task Manager di Windows e in genere vedrai un lungo elenco di processi attivi, molti dei quali eseguiranno più thread. )

In risposta alla tua seconda domanda: la maggior parte dei processi / thread non sono associati alla CPU (ovvero, non sono in esecuzione ininterrottamente e senza interruzioni), ma si fermano e attendono frequentemente il completamento dell'I / O. Durante l'attesa, altri processi / thread possono essere eseguiti senza "rubare" dal codice di attesa (anche su un singolo computer core).


-5

Un thread è un'astrazione che ti consente di scrivere codice semplice come una sequenza di operazioni, beatamente inconsapevole del fatto che il codice sia eseguito interlacciato con altro codice, o parcheggiato in attesa di IO, o (forse un po 'più consapevole di) in attesa di altri thread eventi o messaggi.


Avrei potuto modificarlo aggiungendo altri esempi da quando i downvotes - ma un thread (o processo, in questo contesto quasi nessuna differenza) non sono stati inventati per aumentare le prestazioni, ma piuttosto per semplificare il codice asincrono ed evitare di scrivere macchine a stati complicate che doveva gestire tutti i super-stati possibili nel programma. In effetti, in genere esisteva una CPU anche in server di grandi dimensioni. Sono solo curioso di sapere perché la mia risposta è considerata anti-utile?
Karl

-8

Il punto è che la stragrande maggioranza dei programmatori non capisce come progettare una macchina a stati. Essere in grado di mettere tutto nel proprio thread libera il programmatore dal dover pensare a come rappresentare in modo efficiente lo stato dei diversi calcoli in corso in modo che possano essere interrotti e poi ripresi.

Ad esempio, considera la compressione video, un'attività molto impegnativa per la CPU. Se stai usando uno strumento gui, probabilmente vuoi che l'interfaccia rimanga reattiva (mostra i progressi, rispondi alle richieste di annullamento, ridimensionamento delle finestre, ecc.). Quindi progettate il vostro software di codifica per elaborare un'unità di grandi dimensioni (uno o più frame) alla volta ed eseguirlo nel proprio thread, separato dall'interfaccia utente.

Naturalmente una volta che ti rendi conto che sarebbe stato bello poter salvare lo stato di codifica in corso in modo da poter chiudere il programma per riavviare o giocare a un gioco affamato di risorse, ti rendi conto che avresti dovuto imparare a progettare macchine a stati dal inizio. O quello, o decidi di progettare un nuovo problema di ibernazione del processo del tuo sistema operativo in modo da poter sospendere e riprendere singole app su disco ...


7
Non (del tutto!) Vale -1, ma sul serio, è la cosa più stupida che io abbia sentito qualcuno dire su questo argomento. Ad esempio, non ho problemi nell'implementazione di una macchina a stati. Proprio nessuno. Non mi piace usarli quando ci sono altri strumenti che lasciano un codice più chiaro e più facile da mantenere . Le macchine statali hanno i loro posti e in quei posti non possono essere abbinate. L'interlacciamento delle operazioni ad uso intensivo di CPU con gli aggiornamenti della GUI non è uno di quei posti. Per lo meno le coroutine sono una scelta migliore lì, con il threading ancora migliore.
SOLO IL MIO OPINIONE corretta il

Per tutti coloro che stanno modificando la mia risposta, questo NON è un argomento contro l'uso dei thread! Se riesci a codificare una macchina a stati che è eccezionale e sicuramente ha senso eseguire macchine a stati in thread separati anche se non è necessario. Il mio commento è stato che spesso la scelta di utilizzare i thread è principalmente dovuta al desiderio di evitare di progettare macchine a stati, che molti programmatori considerano "troppo difficili", piuttosto che per altri vantaggi.
R .. GitHub smette di aiutare ICE il
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.