2016-04-11 16 views
8

So che node.js è un I/o singolo thread, asincrono, non bloccante. Ho letto molto su questo. per esempio PHP usa un thread per richiesta ma il nodo usa solo un thread per tutti, in quel modo.Node.js server con più richieste simultanee, come funziona?

Supponiamo che ci siano tre richieste a, b, c che arrivano allo stesso tempo sul server node.js. Tre di queste richieste richiedono una grande operazione di blocco, ad esempio tutti vogliono leggere lo stesso grande file.

Quindi, come vengono accodate le richieste, in quale sequenza verrà eseguita l'operazione di blocco e in quali sequenze verranno inviate le risposte? Ovviamente usando quanti fili?

Per favore dimmi le sequenze dalla richiesta alla risposta per tre richieste.

+0

runtime del nodo è multithreaded. È solo il modello Javascript che esegue un singolo thread. –

risposta

29

Ecco una descrizione di una sequenza di eventi per le tre richieste:

  1. Tre richieste vengono inviate al server web node.js.
  2. Qualsiasi richiesta arrivi in ​​modo frazionale prima che gli altri due attivino il gestore di richieste del server Web e inizieranno l'esecuzione.
  3. Le altre due richieste vanno nella coda degli eventi node.js, in attesa del loro turno. È tecnicamente all'altezza dell'interno dell'implementazione node.js se una richiesta in attesa viene accodata al livello TCP in arrivo o se è accodata all'interno di node.js (non lo so), ma ai fini di questa discussione, tutto quello che importa è che l'evento in arrivo viene messo in coda e non si innescherà fino a quando la prima richiesta non si ferma.
  4. Il primo gestore di richieste verrà eseguito fino a quando non raggiunge un'operazione asincrona (come la lettura di un file) e quindi non ha nient'altro da fare fino al completamento dell'operazione asincrona.
  5. A quel punto, l'operazione di I/O di file asincrono viene avviata e viene restituito il gestore di richiesta originale (viene eseguito con ciò che può fare in quel momento).
  6. Poiché la prima richiesta (che è in attesa di I/O di file) è stata restituita per ora, il motore node.js può ora estrarre l'evento successivo dalla coda degli eventi e avviarlo. Questa sarà la seconda richiesta di arrivare sul server. Passerà attraverso lo stesso processo alla prima richiesta e verrà eseguito finché non avrà nient'altro da fare (e sta anche aspettando l'I/O di file).
  7. Quando la seconda richiesta ritorna al sistema (poiché è in attesa di I/O di file), la terza richiesta può essere avviata. Seguirà lo stesso percorso dei precedenti due.
  8. Quando la terza richiesta ora attende anche l'I/O e ritorna al sistema, node.js è quindi libero di estrarre l'evento successivo dalla coda eventi.
  9. A questo punto, tutti e tre i gestori di richieste sono "in volo" allo stesso tempo. Solo uno in realtà viene eseguito contemporaneamente, ma tutti sono in esecuzione contemporaneamente.
  10. Questo evento successivo nella coda eventi potrebbe essere un altro evento o qualche altra richiesta oppure potrebbe essere il completamento di una delle tre operazioni di I/O di file precedenti. L'evento successivo alla coda inizierà l'esecuzione. Supponiamo che sia la prima operazione di I/O su file della richiesta. A quel punto, chiama la richiamata di completamento associata all'operazione di I/O del file della prima richiesta e quella prima richiesta avvia l'elaborazione dei risultati I/O del file. Questo codice continuerà quindi a funzionare fino a quando non completa l'intera richiesta e restituisce o finché non inizia alcune altre operazioni asincrone (come più I/O di file) e restituisce.
  11. Eventualmente, l'I/O del file della seconda richiesta sarà pronto e quell'evento verrà estratto dalla coda eventi.
  12. Quindi, lo stesso per la terza richiesta e alla fine tutti e tre finiranno.

Quindi, anche se in realtà una sola richiesta è in esecuzione contemporaneamente, più richieste possono essere "in elaborazione" o "in volo" allo stesso tempo. Questo è talvolta chiamato multi-tasking cooperativo piuttosto che un multitasking "pre-emptive" con più thread nativi in ​​cui il sistema può passare liberamente da un thread all'altro in qualsiasi momento, un determinato thread di Javascript viene eseguito finché non ritorna al sistema e quindi e solo allora, può iniziare un altro pezzo di Javascript. Poiché un pezzo di Javascript può avviare operazioni asincrone non bloccanti, il thread di Javascript può tornare al sistema (consentendo l'esecuzione di altri pezzi di Javascript) mentre le operazioni asincrone sono ancora in sospeso. Al termine di tali operazioni, pubblicheranno un evento nella coda degli eventi e quando viene eseguito un altro Javascript e tale evento si posiziona in cima alla coda, verrà eseguito.

Single Threaded

Il punto chiave qui è che un dato filo di Javascript durerà fino a tornare di nuovo al sistema. Se, nel processo di esecuzione, avvia alcune operazioni asincrone (come I/O di file o di rete), quando questi eventi finiscono, inseriscono un evento nella coda degli eventi e quando il motore JS ha terminato di eseguire eventi prima questo evento verrà servito e causerà il richiamo di un callback e tale callback avrà il suo turno di esecuzione.

Questa natura a thread singolo semplifica enormemente la gestione della concorrenza rispetto a un modello a più thread. In un ambiente completamente multi-thread in cui ogni singola richiesta inizia una propria discussione, TUTTI i dati che desiderano essere condivisi, anche una semplice variabile è soggetta a una condizione di competizione e devono essere protetti con un mutex prima che chiunque possa anche solo leggerlo.

In Javascript perché non vi è alcuna esecuzione simultanea di più richieste, non è necessario alcun mutex per l'accesso di variabili condivise semplici. Nel momento in cui un pezzo di Javascript sta leggendo una variabile, per definizione, nessun altro Javascript è in esecuzione in quel momento (singolo thread).

Node.JS fa uso di discussioni

Una distinzione tecnica di nota è che solo l'esecuzione di Javascript è a thread singolo. Gli interni di node.js utilizzano i thread stessi per alcune cose. Ad esempio, l'I/O file asincrono utilizza effettivamente i thread nativi. L'I/O di rete non utilizza effettivamente thread (utilizza la rete basata sugli eventi nativi).

Tuttavia, questo uso di thread all'interno di node.js non influisce direttamente sull'esecuzione di Javascript. C'è sempre solo un singolo thread di esecuzione di Javascript alla volta.

corsa Condizioni

C'è ancora possono essere condizioni di gara per lo stato che è nel mezzo di essere modificato quando viene avviata un'operazione asincrona, ma questo è molto, molto meno comune che in un ambiente multi-thread ed è molto più facile identificare e proteggere questi casi. Come esempio di una condizione di competizione che può esistere, ho un semplice server che prende le letture da diverse sonde di temperatura ogni 10 secondi utilizzando un timer a intervalli. Raccoglie i dati da tutte quelle letture di temperatura e ogni ora scrive quei dati sul disco. Usa I/O asincrono per scrivere i dati sul disco. Tuttavia, dal momento che una serie di operazioni di I/O di file asincrono differenti vengono utilizzate per scrivere i dati su disco, è possibile che il timer intervenga tra alcune di quelle operazioni di I/O di file asincrono che causano i dati in cui si trova il server nel mezzo della scrittura su disco da modificare.Questo è negativo e può causare la scrittura di dati incoerenti. In un mondo semplice, questo potrebbe essere evitato facendo una copia di tutti i dati prima di iniziare a scrivere sul disco per cui se una nuova lettura della temperatura arriva mentre i dati vengono scritti su disco, la copia non sarà influenzato e il codice scriverà comunque un insieme consistente di dati su disco. Ma, nel caso di questo server, i dati possono essere grandi e la memoria sul server è piccola (è un server Raspberry Pi) quindi non è pratico fare una copia in memoria di tutti i dati.

Quindi, il problema è risolto impostando un flag quando i dati sono in procinto di essere scritti su disco e poi cancellare il flag quando i dati viene effettuata in fase di scritti su disco. Se un timer intervallo viene attivato mentre questo flag è impostato, i nuovi dati vengono messi in una coda separata e i dati principali che sono in fase di scrittura su disco NON vengono modificati. Quando i dati vengono scritti su disco, controlla la coda e tutti i dati di temperatura rilevati vengono poi aggiunti ai dati di temperatura in memoria. L'integrità di ciò che è in corso di essere scritta su disco è preservata. Il mio server registra un evento ogni volta che questa "condizione di competizione" viene colpita e i dati vengono messi in coda a causa di esso. E, ecco, succede ogni tanto e il codice per preservare l'integrità dei dati funziona.

+0

gran numero di richieste Supponiamo che (dire 500) ha colpito il server prima di operazioni di I/O dei tre precedenti richieste complete che significa 500 nuove richieste ci sono in coda degli eventi OK! Quindi la risposta per la prima 3 richiesta sarà in sospeso a causa di quelle 500 nuove richieste. È buona? – Siddharth

+0

@Siddharth - Si dovrebbe verificare come node.js assegna la priorità agli eventi di completamento I/O rispetto agli eventi di nuova connessione in entrata. Concettualmente, questo non dovrebbe essere un problema in qualunque modo funzioni, ma non so quali eventi abbiano priorità nel modo in cui node.js gestisce le cose. Logicamente, si potrebbe pensare che sarebbe la priorità servire connessioni che hanno già iniziato, ma che ci si sia dovuto scrivere su un banco di prova ed eseguirlo su diverse piattaforme Node.JS o studiare il codice sorgente per sapere con certezza. – jfriend00

+0

@ jfriend00 hi non ho una formazione in informatica ma vedo un sacco di lettere 'I/O' Gradirei se si può spiegare un po 'su di esso. come quando lo usi in questa frase: "l'operazione di I/O di file asincrono viene avviata" vuoi dire che questo è il momento in cui l'interprete o quello che viene chiamato legge il file che l'OP sta parlando? Perché lo chiamano un "file asincrono"? btw penso che I/O significhi input/output. e ciò significa operazioni che vengono applicate a qualcosa. E quando la gente lo menziona per il nodo è principalmente req e risposte (server)? qualsiasi risposta aiuterà –

Problemi correlati