2010-05-08 15 views
9

Immagina di avere due (tre, quattro, qualunque) attività che devono essere eseguite in parallelo. Ora, il modo più semplice per farlo sarebbe creare thread separati e dimenticarsene. Ma su una semplice vecchia CPU single-core che significherebbe un sacco di cambio di contesto - e sappiamo tutti che il cambio di contesto è grande, cattivo, lento e generalmente semplicemente malvagio. Dovrebbe essere evitato, giusto?Quanto costa un interruttore di contesto? È meglio implementare un commutatore di attività manuale piuttosto che fare affidamento sui thread del sistema operativo?

In tale nota, se sto scrivendo il software da zero in ogni caso, potrei fare il miglio supplementare e implementare il mio passaggio di attività. Dividere ogni attività in parti, salvare lo stato tra di esse e quindi passare da una parte all'altra all'interno di un singolo thread. Oppure, se rilevo che ci sono più core CPU, potrei semplicemente assegnare ogni attività a un thread separato e tutto andrebbe bene.

La seconda soluzione ha il vantaggio di adattarsi al numero di core CPU disponibili, ma il commutatore di attività manuale sarà davvero più veloce di quello nel core del SO? Soprattutto se sto cercando di rendere il tutto generico con uno TaskManager e uno ITask, ecc.?

Chiarimento: Sono uno sviluppatore Windows quindi sono principalmente interessato alla risposta per questo sistema operativo, ma sarebbe molto interessante scoprire anche altri sistemi operativi. Quando scrivi la tua risposta, specifica per quale sistema operativo si tratta.

Ulteriori chiarimenti: OK, quindi questo non è nel contesto di una particolare applicazione. È davvero una domanda generale, il risultato delle mie riflessioni sulla scalabilità. Se voglio che la mia applicazione riduca e utilizzi efficacemente le future CPU (e anche diverse CPU di oggi), devo farla multithreaded. Ma quanti fili? Se faccio un numero costante di thread, il programma si esibirà in modo subottimale su tutte le CPU che non hanno lo stesso numero di core.

Idealmente il numero di thread sarebbe determinato in fase di esecuzione, ma pochi sono i compiti che possono essere realmente suddivisi in un numero arbitrario di parti in fase di esecuzione. Molte attività tuttavia possono essere suddivise in un numero costante piuttosto grande di thread in fase di progettazione. Quindi, ad esempio, se il mio programma fosse in grado di generare 32 thread, utilizzerebbe già tutti i core con CPU fino a 32-core, il che è ancora molto lontano nel futuro (credo). Ma su una semplice CPU single-core o dual-core significherebbe un sacco di commutazione di contesto, che rallenterebbe le cose.

Quindi la mia idea sulla commutazione manuale delle attività. In questo modo si potevano creare 32 fili "virtuali" che sarebbero mappati su un numero di thread reali come ottimale, e il "cambio di contesto" sarebbe fatto manualmente. La domanda è: il sovraccarico del mio "cambio di contesto" manuale sarebbe inferiore a quello del cambio di contesto OS?

Ovviamente, tutto ciò si applica ai processi legati alla CPU, come i giochi. Per la tua applicazione CRUD run-of-the-mill questo ha poco valore. Tale applicazione è realizzata al meglio con un thread (al massimo due).

+0

Quale sistema operativo sei interessato/a? Questo varia * ampiamente * tra i sistemi operativi. –

+1

Fondamentalmente sono un programmatore di Windows, ma sarebbe interessante conoscere anche altri sistemi operativi. Ho cercato di rendere la domanda piuttosto agonostica per il sistema operativo. –

+0

@Vilx Questa domanda per sua stessa natura non può mai essere indipendente dal sistema operativo. – Cromulent

risposta

5

Non vedo come un commutatore di attività manuale potrebbe essere più veloce poiché il kernel del sistema operativo sta ancora commutando altri processi, incluso il vostro anche in stato di esecuzione. Sembra un'ottimizzazione prematura e uno spreco potenzialmente enorme di sforzi.

Se il sistema non sta facendo altro, è probabile che non si disporrà comunque di un numero elevato di switch di contesto. Il thread userà il suo timeslice, lo scheduler del kernel vedrà che non è necessario eseguire nient'altro e tornare direttamente al thread. Anche il sistema operativo farà il possibile per evitare di spostare i thread tra le CPU in modo da beneficiare della memorizzazione nella cache.

Se la CPU è realmente vincolata, rilevare il numero di CPU e avviare molti thread. Dovresti vedere quasi il 100% di utilizzo della CPU. In caso contrario, non si è completamente vincolati alla CPU e forse la risposta è avviare i thread N + X. Per i processi molto legati all'IO, si avvierebbe un (grande) multiplo del conteggio della CPU (cioè i server Web con traffico elevato eseguono 1000+ thread).

Infine, per riferimento, entrambi gli scheduler di Windows e Linux si svegliano ogni millisecondo per verificare se è necessario eseguire un altro processo. Quindi, anche su un sistema inattivo vedrete oltre 1000 interruttori di contesto al secondo. Su sistemi pesantemente caricati, ho visto oltre 10.000 al secondo per CPU senza problemi significativi.

+0

In altre parole, anche se avessi fatto 32 thread legati alla CPU su un sistema single-core, il rallentamento rispetto a una soluzione a thread singolo sarebbe trascurabile? –

+0

Non penso che l'overhead sarebbe trascurabile, volevo solo dire che una CPU può gestire un gran numero di switch di contesto e continuare a lavorare. Avresti bisogno di eseguire alcuni test per determinare il sovraccarico e se stai bene con esso. Dipende da quanto tempo viene eseguito questo processo: 1 ms di sovraccarico per un'attività che richiede 10 secondi, probabilmente non importa; forse 1 secondo di overhead sarebbe.È abbastanza facile ottenere il numero di CPU su un sistema; hai già un algoritmo facile da separare, quindi _questo overhead potrebbe non essere accettabile e dovresti eseguire un singolo thread su un sistema single core. – AngerClown

3

Le macchine Windows single-core si estingueranno nei prossimi anni, quindi in genere scrivo un nuovo codice con l'ipotesi che il multi-core sia il caso comune. Direi di andare con la gestione dei thread del sistema operativo, che si occuperà automaticamente della concorrenza offerta dall'hardware, ora e in futuro.

Non so cosa fa l'applicazione, ma a meno che non si abbiano più attività legate all'elaborazione, dubito che i commutatori di contesto siano un collo di bottiglia significativo nella maggior parte delle applicazioni. Se le tue attività si bloccano su I/O, allora non otterrai molti vantaggi dal provare a utilizzare il sistema operativo.

+0

Naturalmente questo si applica solo ai processi associati alla CPU. Non intendevo nient'altro. Ma anche quando si ha un processo legato alla CPU e si punta a una CPU multi-core, come si scrive il processo in modo che sia garantito l'utilizzo ottimale di tutti i core disponibili, indipendentemente dal fatto che siano 2 o 32? –

+0

OpenMP rende piuttosto semplice ridimensionare automaticamente le cose al numero di core. L'API di Windows fornisce pool di thread, che dovrebbero crescere e ridursi automaticamente in base alla disponibilità e all'utilizzo del processore. Oppure vedi http://stackoverflow.com/questions/150355/programmatically-find-the-number-of-cores-on-a-machine se vuoi conoscere il numero di core. –

5

L'unico vantaggio dell'interruttore manuale che posso vedere è che è possibile controllare meglio dove e quando avviene l'interruttore.Il posto ideale è, naturalmente, dopo il, è stata completata un'unità di lavoro in modo da poterla copiare tutti insieme. Questo ti fa risparmiare una cache.

Mi raccomando di non spendere i vostri sforzi per questo.