Perché Node.js è a thread singolo? [chiuso]


255

Nei server Web basati su PHP (o Java / ASP.NET / Ruby) ogni richiesta client viene istanziata su un nuovo thread. Ma in Node.js tutti i client girano sullo stesso thread (possono persino condividere le stesse variabili!) Comprendo che le operazioni di I / O sono basate sugli eventi, quindi non bloccano il loop del thread principale.

Quello che non capisco è PERCHÉ l'autore di Node ha scelto di essere single thread? Rende le cose difficili. Ad esempio, non riesco a eseguire una funzione intensiva della CPU perché blocca il thread principale (e le nuove richieste client sono bloccate), quindi devo generare un processo (il che significa che devo creare un file JavaScript separato ed eseguire un altro processo nodo su esso). Tuttavia, in PHP cpu le attività intensive non bloccano altri client perché, come ho già detto, ogni client si trova su un thread diverso. Quali sono i suoi vantaggi rispetto ai server web multi-thread?

Nota: ho usato il clustering per aggirare questo, ma non è carino.


12
Di recente ho visto un buon video (29 minuti) che spiega alcuni dei concetti alla base di Node. Penso anche che il ragazzo parli di compiti intensivi della CPU e brevemente come gestirli: youtube.com/watch?v=L0pjVcIsU6A
whirlwin

24
Potresti saperlo, ma per essere chiari Node.js non è a thread singolo. Il codice JavaScript viene eseguito a thread singolo, ma le operazioni di I / O e altre operazioni che i plug-in possono eseguire a corto di un pool di thread. Node.js offre molti dei vantaggi del multithreading senza dover gestire il codice multithread. Inoltre, gli autori di Node.js non hanno scelto la natura a thread singolo di JavaScript, lo hanno fatto gli autori di JavaScript. Non riesco a pensare a un modo in cui JS potrebbe funzionare in un contesto multithread, ma anche se ci fosse, V8 non è scritto in quel modo che è ciò che Node.js utilizza come motore JavaScript.
Brad

5
PHP è più single-thread di JavaScript. Probabilmente stai pensando a moduli server come FastCGI o mod_php. Quindi stai effettivamente confrontando Node.js con Apache, Nginx o IIS, non con PHP, Java o Ruby.
Álvaro González,

34
Il nodo non è a thread singolo. È un malinteso popolare. Anche semplice node -e 'setTimeout(()=>{},1000);' & ps -T h $! | wc -l; kill $!visualizza cinque thread sul mio sistema. Il ciclo di eventi principale è a thread singolo (non avrebbe molto senso se non lo fosse) ma Node è fortemente multi-thread e puoi scrivere applicazioni a singolo processo multi-thread se lo desideri. Mi piacerebbe scrivere una risposta esauriente al riguardo, ma alcune persone hanno deciso di chiudere la tua domanda, quindi non posso. Sto votando per riaprirlo. Se ottiene più voti e viene riaperto, per favore menzionami nel commento.
rsp,

2
@rsp grazie per il tuo commento, ma nel thread principale intendevo non correlato agli I / O. se stai facendo qualcosa di cpu come un big for loop che fa qualcosa, il server smette di elaborare le connessioni. ciò significa che il server non è utilizzabile al momento. quindi ci lasciamo gli hack come i cluster solo per fare qualcosa di così semplice invece che intralciare intrinsecamente ogni connessione come fanno la maggior parte dei server. jxcore.com ha provato a risolvere questo problema, ma in seguito utilizza plug-in di nodi speciali / modificati, il che lo rende sostanzialmente inutilizzabile.
foreyez,

Risposte:


292

Node.js è stato creato esplicitamente come esperimento nell'elaborazione asincrona. La teoria era che l'elaborazione asincrona su un singolo thread potesse fornire più prestazioni e scalabilità con carichi Web tipici rispetto alla tipica implementazione basata su thread.

E tu sai cosa? Secondo me questa teoria è stata confermata. Un'app node.js che non esegue attività ad uso intensivo di CPU può eseguire migliaia di connessioni simultanee in più rispetto ad Apache o IIS o altri server basati su thread.

La natura a thread singolo e asincrono rende le cose complicate. Ma pensi onestamente che sia più complicato del threading? Una condizione di gara può rovinare l'intero mese! O svuota il tuo pool di thread a causa di alcune impostazioni da qualche parte e osserva il tempo di risposta lento a una scansione! Per non parlare dei deadlock, delle inversioni prioritarie e di tutte le altre rotazioni associate al multithreading.

Alla fine, non penso che sia universalmente migliore o peggiore; è diverso, a volte è meglio, a volte no. Usa lo strumento giusto per il lavoro.


26
Ma i server Web in genere fanno MOLTO materiale ad alta intensità di CPU, non è SOLO il recupero del database. Dobbiamo elaborare ciò che recuperiamo e fare molte logiche aziendali molto spesso prima di servirlo al cliente.
foreyez,

22
Quindi generano solo lavoratori, bene! Questo è l'intero accordo con Node.js. Roba pesante può essere eseguita in un altro processo e tu ne elabori si traduce in un callback leggero.
MaiaVictor

7
Il problema è che esiste un processo a livello di sistema operativo in esecuzione per lavoratore. Li vedrai usando il comando "ps". Quindi questo significa potenzialmente migliaia di processi in esecuzione sulla macchina in una sola volta: è pazzesco!
foreyez,

9
@foreyez, non è necessario un processo per utente. Puoi scegliere come suddividere il carico. Inoltre, non tutti stanno facendo un sacco di roba intensiva per la CPU. Il nodo è uno strumento per un lavoro ... forse non il tuo lavoro, ma molti tipi di lavori.
Brad

15
In realtà, vorrei che @foreyez eseguisse il backup di quell'affermazione secondo cui "i server Web in genere su ALOT (sic) di roba ad alta intensità di CPU". Nella mia esperienza, non lo fanno. O forse la mia definizione di "cpu intensive" differisce dalla sua. La conversione dei dati di prodotto in un'interfaccia utente non richiede molta CPU, né calcola ordini o simili. Gran parte del web è piuttosto transazionale. Le cose che richiedono molta CPU sono cose come la conversione di video, la conversione di formati di immagine, ecc. Gran parte di ciò è dovuto all'I / O dei file che, in realtà, il nodo fa abbastanza bene. E semplifica lo scaricamento su un altro processo dedicato alla conversione.
Paul

62

Il problema con il modello "un thread per richiesta" per un server è che non si adattano bene per diversi scenari rispetto al modello di thread del ciclo di eventi.

In genere, negli scenari di I / O intensivi le richieste trascorrono la maggior parte del tempo in attesa del completamento dell'I / O. Durante questo periodo, nel modello "un thread per richiesta", le risorse collegate al thread (come la memoria) non sono utilizzate e la memoria è il fattore limitante. Nel modello di loop di eventi, il thread di loop seleziona l'evento successivo (I / O terminato) da gestire. Quindi il thread è sempre occupato (se lo si programma correttamente ovviamente).

Il modello del circuito degli eventi, come tutte le novità, sembra brillante e la soluzione per tutti i problemi, ma quale modello utilizzare dipenderà dallo scenario che devi affrontare. Se si dispone di uno scenario di I / O intensivo (come un proxy), il modello base di eventi governerà, mentre uno scenario intensivo della CPU con un basso numero di processi simultanei funzionerà meglio con il modello basato su thread.

Nel mondo reale la maggior parte degli scenari sarà un po 'nel mezzo. Dovrai bilanciare la reale necessità di scalabilità con la complessità di sviluppo per trovare l'architettura corretta (ad esempio avere un front-end di base di eventi che deleghi al back-end per le attività ad alta intensità di CPU. Il front-end utilizzerà poche risorse in attesa dell'attività risultato.) Come con qualsiasi sistema distribuito, richiede un certo sforzo per farlo funzionare.

Se stai cercando il proiettile d'argento che si adatta a qualsiasi scenario senza alcuno sforzo, finirai con un proiettile nel tuo piede.


8
Node.js è limitato all'elaborazione solo degli eventi a causa della mancanza del supporto multithreading v8. Bene, il linguaggio javascript stesso manca delle funzionalità necessarie, quindi qualsiasi implementazione finirà per essere complicata. Questo è il principale colpevole di Node.js, secondo me. In altre lingue puoi scegliere quello che vuoi. O qualche ibrido di entrambi i modelli, come Java NIO.
FrameGrace,

2
@Kazaag, server web moderni fanno mantenere un ThreadPool. Non generano semplicemente una nuova discussione per caricamento di pagina. Quelli sono i server web più vecchi.
Pacerier,

1
@Pacerier Non ho mai detto che viene generato un nuovo thread, ma ogni thread viene assegnato a una richiesta fino al termine della richiesta.
Kazaag,

2
@Kazaag Non è assolutamente una regola generale che "ogni thread è assegnato a una richiesta fino al termine della richiesta". Vale a dire in .Net (compresa l'elaborazione delle richieste HTTP) si può e si dovrebbe usare la programmazione asincrona (Task based) e questo rilascerà i thread in attesa del completamento dell'I / O e di altre operazioni asincrone. Ciò è applicabile anche alla programmazione di alto livello, vale a dire controller MVC / API. Quindi in pratica potrebbero esserci 20 richieste HTTP in sospeso ma solo un thread attivo.
user3285954

29

Per farla breve, il nodo disegna da V8, che è internamente a thread singolo. Esistono modi per aggirare i vincoli per le attività ad alta intensità di CPU.

Ad un certo punto (0.7) gli autori hanno cercato di introdurre gli isolati come un modo per implementare più thread di calcolo, ma alla fine sono stati rimossi: https://groups.google.com/forum/#!msg/nodejs/zLzuo292hX0/F7gqfUiKi2sJ


Hai ulteriori informazioni su questo "isolato"?
Pacerier,
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.