risposta-alla-domanda-sullo-sviluppo-web-bd.com

Discussioni vs processi in Linux

Di recente ho sentito alcune persone dire che in Linux è quasi sempre meglio usare i processi anziché i thread, poiché Linux è molto efficiente nella gestione dei processi e perché ci sono così tanti problemi (come il blocco) associati ai thread. Tuttavia, sono sospettoso, perché sembra che i thread possano dare un notevole aumento delle prestazioni in alcune situazioni.

Quindi la mia domanda è, di fronte a una situazione che thread e processi potrebbero gestire abbastanza bene, dovrei usare processi o thread? Ad esempio, se stavo scrivendo un server Web, dovrei usare processi o thread (o una combinazione)?

237
user17918

Linux usa un modello di threading 1-1, con (per il kernel) nessuna distinzione tra processi e thread - tutto è semplicemente un compito eseguibile. *

Su Linux, la chiamata di sistema clone clona un'attività, con un livello di condivisione configurabile, tra cui:

  • CLONE_FILES: Condividi la stessa tabella descrittore di file (invece di creare una copia)
  • CLONE_PARENT: Non impostare una relazione genitore-figlio tra la nuova attività e la vecchia (altrimenti, getppid() = parent's getpid())
  • CLONE_VM: Condividi lo stesso spazio di memoria (invece di creare una COW copy)

fork() chiama clone( condivisione minima ) e pthread_create() chiama clone( maggior condivisione ). **

forking costa un po 'più di pthread_create a causa della copia di tabelle e della creazione di mapping COW per la memoria, ma gli sviluppatori del kernel Linux hanno cercato (e sono riusciti) di ridurre al minimo tali costi.

Il passaggio da un'attività all'altra, se condividono lo stesso spazio di memoria e varie tabelle, sarà un po 'più economico rispetto a se non sono condivisi, perché i dati potrebbero già essere caricati nella cache. Tuttavia, il cambio di attività è ancora molto veloce anche se nulla è condiviso - questo è qualcos'altro che gli sviluppatori del kernel Linux cercano di garantire (e riescono a garantire).

In effetti, se utilizzi un sistema multiprocessore, la condivisione non può effettivamente essere utile per le prestazioni: se ogni attività è in esecuzione su un processore diverso, la sincronizzazione della memoria condivisa è costosa.


* Semplificato. CLONE_THREAD Causa la condivisione dei segnali (che richiede CLONE_SIGHAND, Che condivide la tabella del gestore dei segnali).

** Semplificato. Esistono sia syscalls SYS_fork Che SYS_clone, Ma nel kernel, sys_fork E sys_clone Sono entrambi involucri molto sottili attorno allo stesso do_fork, che a sua volta è un wrapper sottile attorno a copy_process. Sì, i termini process, thread e task sono usati in modo abbastanza intercambiabile nel kernel di Linux ...

307
ephemient

Linux (e in effetti Unix) ti offre una terza opzione.

Opzione 1 - processi

Crea un eseguibile autonomo che gestisca una parte (o tutte le parti) dell'applicazione e invocalo separatamente per ogni processo, ad es. il programma esegue copie di se stesso per delegare compiti a.

Opzione 2 - discussioni

Crea un eseguibile autonomo che si avvia con un singolo thread e crea thread aggiuntivi per eseguire alcune attività

Opzione 3 - forcella

Disponibile solo su Linux/Unix, questo è un po 'diverso. Un processo biforcato è in realtà un proprio processo con un proprio spazio di indirizzi - non c'è nulla che il bambino possa fare (normalmente) per influenzare lo spazio di indirizzi dei suoi genitori o fratelli (a differenza di un thread) - quindi si ottiene una maggiore robustezza.

Tuttavia, le pagine di memoria non vengono copiate, ma sono copia su scrittura, quindi di solito viene utilizzata meno memoria di quanto si possa immaginare.

Prendi in considerazione un programma per server Web che consta di due passaggi:

  1. Leggi i dati di configurazione e di runtime
  2. Servire le richieste di pagina

Se hai utilizzato i thread, il passaggio 1 verrebbe eseguito una volta e il passaggio 2 in più thread. Se sono stati utilizzati processi "tradizionali", è necessario ripetere i passaggi 1 e 2 per ciascun processo e duplicare la memoria per memorizzare i dati di configurazione e di runtime. Se hai usato fork (), puoi eseguire il passaggio 1 una volta, quindi fork (), lasciando in memoria i dati di runtime e la configurazione, non toccati, non copiati.

Quindi ci sono davvero tre scelte.

57
MarkR

Dipende da molti fattori. I processi sono più pesanti dei thread e hanno un costo di avvio e spegnimento più elevato. La comunicazione tra processi (IPC) è anche più dura e più lenta della comunicazione interthread.

Al contrario, i processi sono più sicuri e più sicuri dei thread, poiché ogni processo viene eseguito nel proprio spazio di indirizzi virtuale. Se un processo si arresta in modo anomalo o ha un sovraccarico del buffer, non influisce affatto su nessun altro processo, mentre se un thread si arresta in modo anomalo, elimina tutti gli altri thread nel processo e se un thread ha un sovraccarico del buffer, si apre un buco di sicurezza in tutti i thread.

Pertanto, se i moduli dell'applicazione possono essere eseguiti principalmente in modo indipendente con poca comunicazione, è consigliabile utilizzare i processi se è possibile permettersi i costi di avvio e spegnimento. Il successo di IPC sarà minimo e sarai leggermente più sicuro contro bug e falle di sicurezza. Se hai bisogno di ogni bit di prestazione puoi ottenere o avere molti dati condivisi (come come strutture dati complesse), vai con i thread.

50
Adam Rosenfield

Altri hanno discusso delle considerazioni.

Forse la differenza importante è che nei processi di Windows sono pesanti e costosi rispetto ai thread, e in Linux la differenza è molto più piccola, quindi l'equazione si bilancia in un punto diverso.

10
dmckee

C'era una volta Unix e in questa buona vecchia Unix c'era un sacco di spese generali per i processi, quindi quello che alcune persone intelligenti hanno fatto è stato creare thread, che avrebbero condiviso lo stesso spazio di indirizzi con il processo padre e avevano solo bisogno di un contesto ridotto switch, che renderebbe il cambio di contesto più efficiente.

In un Linux contemporaneo (2.6.x) non c'è molta differenza nelle prestazioni tra un cambio di contesto di un processo rispetto a un thread (solo la roba MMU è aggiuntiva per il thread). il problema con lo spazio degli indirizzi condiviso, il che significa che un puntatore difettoso in un thread può danneggiare la memoria del processo padre o un altro thread all'interno dello stesso spazio indirizzo.

Un processo è protetto dalla MMU, quindi un puntatore difettoso causerà solo un segnale 11 e nessuna corruzione.

In generale utilizzerei i processi (non molto overover del contesto in Linux, ma protezione della memoria a causa della MMU), ma se avessi bisogno di una classe scheduler in tempo reale, che è una tazza di tè diversa tutti insieme.

Perché pensi che i thread abbiano un così grande guadagno in termini di prestazioni su Linux? Hai dei dati per questo o è solo un mito?

8
robert.berger

Quanto sono strettamente collegati i tuoi compiti?

Se possono vivere indipendentemente l'uno dall'altro, quindi utilizzare i processi. Se si basano l'uno sull'altro, utilizzare i thread. In questo modo è possibile interrompere e riavviare un processo errato senza interferire con il funzionamento delle altre attività.

5
Robert

A complicare ulteriormente le cose, esiste qualcosa come thread-local storage e la memoria condivisa Unix.

L'archiviazione locale di thread consente a ciascun thread di avere un'istanza separata di oggetti globali. L'unica volta che l'ho usato è stato durante la costruzione di un ambiente di emulazione su Linux/Windows, per il codice dell'applicazione eseguito in un RTOS. Nel RTOS ogni attività era un processo con il proprio spazio di indirizzi, nell'ambiente di emulazione, ogni attività era un thread (con uno spazio di indirizzi condiviso). Usando TLS per cose come i singoli, sono stati in grado di avere un'istanza separata per ogni thread, proprio come nell'ambiente 'real' RTOS.

La memoria condivisa può (ovviamente) offrire i vantaggi in termini di prestazioni di avere più processi che accedono alla stessa memoria, ma a costo/rischio di dover sincronizzare correttamente i processi. Un modo per farlo è quello di avere un processo creare una struttura di dati nella memoria condivisa e quindi inviare un handle a quella struttura tramite la comunicazione tra processi tradizionale (come una pipa denominata).

4
KeyserSoze

La decisione tra thread/processo dipende un po 'da cosa lo userete. Uno dei vantaggi di un processo è che ha un PID e può essere ucciso senza interrompere anche il genitore.

Per un esempio reale di un server Web, Apache 1.3 supportava solo più processi, ma in 2.0 hanno aggiunto n'astrazione in modo da poter passare da uno all'altro. Commentisembrato concordano sul fatto che i processi sono più robusti ma i thread possono offrire prestazioni leggermente migliori (tranne per le finestre in cui le prestazioni per i processi fanno schifo e tu voglio solo usare le discussioni).

3
hlovdal

Dovrei essere d'accordo con quello che hai sentito. Quando eseguiamo il benchmark del nostro cluster (xhpl e simili), otteniamo sempre prestazioni significativamente migliori con i processi sui thread. </anecdote>

3
eduffy

Nel mio recente lavoro con LINUX è una cosa di cui tenere conto sono le librerie. Se si utilizzano i thread, assicurarsi che tutte le librerie che è possibile utilizzare tra i thread siano thread-safe. Questo mi ha bruciato un paio di volte. In particolare libxml2 non è thread-out pronto all'uso. Può essere compilato con thread sicuro ma non è quello che ottieni con aptitude install.

3
aal8

Per la maggior parte dei casi preferirei i processi rispetto ai thread. i thread possono essere utili quando si ha un'attività relativamente più piccola (overhead del processo >> tempo impiegato da ciascuna unità di attività divisa) e c'è una necessità di condivisione della memoria tra di loro. Pensa a una vasta gamma. Inoltre (offtopic), si noti che se l'utilizzo della CPU è pari o vicino al 100 percento, il multithreading o l'elaborazione non trarranno alcun vantaggio. (infatti peggiorerà)

2
neal aise

Penso che tutti abbiano fatto un ottimo lavoro nel rispondere alla tua domanda. Sto solo aggiungendo ulteriori informazioni sul thread rispetto al processo in Linux per chiarire e riassumere alcune delle risposte precedenti nel contesto del kernel. Quindi, la mia risposta riguarda il codice specifico del kernel in Linux. Secondo la documentazione del kernel Linux, non esiste una chiara distinzione tra thread rispetto a processo tranne che thread utilizza spazio di indirizzi virtuali condivisi diversamente dal processo. Inoltre, il kernel di Linux usa il termine "task" per fare riferimento a processo e thread in generale.

"Non ci sono strutture interne che implementano processi o thread, invece c'è una struttura task_struct che descrive un'unità di pianificazione astratta chiamata task"

Inoltre, secondo Linus Torvalds, NON dovresti assolutamente pensare al processo rispetto al thread e perché è troppo limitante e l'unica differenza è COE o Context of Execution in termini di "separare lo spazio degli indirizzi dal genitore" o lo spazio degli indirizzi condiviso. In effetti usa un esempio di web server per esprimere il suo punto qui (che consiglio vivamente di leggere).

Credito completo per documentazione del kernel linux

1
grepit

Discussioni -> Le discussioni condividono uno spazio di memoria, è un'astrazione della CPU, è leggera. Processi -> I processi hanno il loro spazio di memoria, è un'astrazione di un computer. Per parallelizzare l'attività è necessario astrarre una CPU. Tuttavia, i vantaggi dell'utilizzo di un processo su un thread sono la sicurezza, la stabilità mentre un thread utilizza meno memoria rispetto al processo e offre minore latenza. Un esempio in termini di web sarebbe chrome e firefox. In caso di Chrome ogni scheda è un nuovo processo, quindi l'utilizzo della memoria di chrome è maggiore di firefox, mentre la sicurezza e la stabilità fornite sono migliori di firefox. La sicurezza qui fornita da chrome è migliore, poiché ogni scheda è un nuovo processo in cui la scheda diversa non può curiosare) lo spazio di memoria di un determinato processo.