Quale sarebbe meglio per attività simultanee su node.js? Fibre? Web-lavoratori? o thread?


111

Qualche tempo fa sono incappato in node.js e mi piace molto. Ma presto ho scoperto che non aveva la capacità di eseguire attività che richiedono molta CPU. Quindi, ho iniziato a cercare su Google e ho ottenuto queste risposte per risolvere il problema: Fibre, Webworkers e Thread (thread-a-gogo). Ora quale usare è una confusione e uno di questi deve assolutamente essere usato - dopotutto qual è lo scopo di avere un server che è solo bravo a IO e nient'altro? Suggerimenti necessari!

AGGIORNARE:

Stavo pensando a una via di ritardo; ho solo bisogno di suggerimenti su di esso. Ora, quello che ho pensato è stato questo: Facciamo alcuni thread (usando thread_a_gogo o forse webworkers). Ora, quando ne abbiamo bisogno di più, possiamo crearne di più. Ma ci sarà qualche limite al processo di creazione. (non implicito dal sistema ma probabilmente a causa dell'overhead). Ora, quando superiamo il limite, possiamo eseguire il fork di un nuovo nodo e iniziare a creare thread su di esso. In questo modo, può andare avanti fino a raggiungere un certo limite (dopotutto, anche i processi hanno un grande sovraccarico). Quando viene raggiunto questo limite, iniziamo ad accodare le attività. Ogni volta che un thread diventa libero, gli verrà assegnata una nuova attività. In questo modo, può andare avanti senza problemi.

Quindi, questo è quello che ho pensato. Questa idea è buona? Sono un po 'nuovo a tutto questo processo e alle cose dei thread, quindi non ho alcuna esperienza in questo. Per favore condividi le tue opinioni.

Grazie. :)


Nota: i lavoratori sono una specifica del browser, non una funzione Javascript.
FredTheWebGuy

Bene, lo vedo. La mia domanda riguardava node.js - codice server e non lato client!
Parth Thakkar

Solo un chiarimento: vedo che la domanda originale riguardava i Webworkers in NodeJs, il che è impossibile: NodeJs usa "Threads". Tuttavia, è presente un modulo NodeJS fluttuante che consente la sintassi WebWorker all'interno del runtime di NodeJs.
FredTheWebGuy

Risposte:


331

Il nodo ha un paradigma completamente diverso e una volta catturato correttamente, è più facile vedere questo modo diverso di risolvere i problemi. Non hai mai bisogno di più thread in un'applicazione Node (1) perché hai un modo diverso di fare la stessa cosa. Crei più processi; ma è molto molto diverso da, ad esempio, come fa l'mpm Prefork di Apache Web Server.

Per ora, pensiamo di avere un solo core della CPU e svilupperemo un'applicazione (alla maniera di Node) per fare un po 'di lavoro. Il nostro compito è elaborare un file di grandi dimensioni che scorre sul suo contenuto byte per byte. Il modo migliore per il nostro software è iniziare il lavoro dall'inizio del file, seguirlo byte per byte fino alla fine.

- Ehi, Hasan, suppongo che tu sia un principiante o una scuola molto vecchia dai tempi di mio nonno !!! Perché non crei alcuni thread e lo rendi molto più veloce?

- Oh, abbiamo solo un core della CPU.

-- E allora? Crea dei thread amico, rendilo più veloce!

- Non funziona così. Se creo dei thread, lo renderò più lento. Perché aggiungerò un sacco di overhead al sistema per passare da un thread all'altro, cercando di dare loro una giusta quantità di tempo e, all'interno del mio processo, tentando di comunicare tra questi thread. Oltre a tutti questi fatti, dovrò anche pensare a come dividere un singolo lavoro in più pezzi che possono essere eseguiti in parallelo.

- Va bene, va bene, vedo che sei povero. Usiamo il mio computer, ha 32 core!

- Wow, sei fantastico mio caro amico, grazie mille. Lo apprezzo!

Poi torniamo al lavoro. Ora abbiamo 32 core cpu grazie al nostro ricco amico. Le regole che dobbiamo rispettare sono appena cambiate. Ora vogliamo utilizzare tutta questa ricchezza che ci viene data.

Per utilizzare più core, dobbiamo trovare un modo per dividere il nostro lavoro in parti che possiamo gestire in parallelo. Se non fosse Node, useremmo i thread per questo; 32 thread, uno per ogni core della cpu. Tuttavia, poiché abbiamo Node, creeremo 32 processi Node.

I thread possono essere una buona alternativa ai processi Node, forse anche un modo migliore; ma solo in un tipo specifico di lavoro in cui il lavoro è già definito e abbiamo il controllo completo su come gestirlo. Oltre a questo, per ogni altro tipo di problema in cui il lavoro viene dall'esterno in un modo su cui non abbiamo il controllo e vogliamo rispondere il più rapidamente possibile, il modo di Node è indiscutibilmente superiore.

- Ehi, Hasan, lavori ancora a thread singolo? Cosa c'è di sbagliato in te, amico? Ti ho appena fornito quello che volevi. Non hai più scuse. Crea thread, fallo funzionare più velocemente.

- Ho diviso il lavoro in pezzi e ogni processo lavorerà su uno di questi pezzi in parallelo.

- Perché non crei thread?

- Scusa, non credo sia utilizzabile. Puoi prendere il tuo computer se vuoi?

- No okay, sto bene, solo che non capisco perché non usi i thread?

- Grazie per il computer. :) Ho già diviso il lavoro in pezzi e creo processi per lavorare su questi pezzi in parallelo. Tutti i core della CPU saranno completamente utilizzati. Potrei farlo con i thread invece che con i processi; ma Node ha questo modo e il mio capo Parth Thakkar vuole che usi Node.

- Va bene, fammi sapere se ti serve un altro computer. : p

Se creo 33 processi, invece di 32, lo scheduler del sistema operativo metterà in pausa un thread, avvierà l'altro, lo metterà in pausa dopo alcuni cicli, riavvierà l'altro ... Questo è un sovraccarico non necessario. Io non lo voglio. In effetti, su un sistema con 32 core, non vorrei nemmeno creare esattamente 32 processi, 31 può essere più bello . Perché non è solo la mia applicazione che funzionerà su questo sistema. Lasciare un po 'di spazio per altre cose può andare bene, soprattutto se abbiamo 32 stanze.

Credo che ora siamo sulla stessa pagina sull'utilizzo completo dei processori per attività ad alta intensità di CPU .

- Hmm, Hasan, mi dispiace di averti preso in giro un po '. Credo di capirti meglio adesso. Ma c'è ancora qualcosa per cui ho bisogno di una spiegazione: qual è tutto il brusio dell'esecuzione di centinaia di thread? Ho letto ovunque che i thread sono molto più veloci da creare e stupidi rispetto ai processi di fork? Esegui il fork dei processi invece dei thread e pensi che sia il massimo che potresti ottenere con Node. Quindi Node non è appropriato per questo tipo di lavoro?

- Nessun problema, anch'io sono a posto. Tutti dicono queste cose quindi penso di essere abituato a sentirle.

-- Così? Node non va bene per questo?

- Node è perfettamente adatto a questo, anche se anche i thread possono essere buoni. Per quanto riguarda l'overhead di creazione di thread / processi; su cose che ripeti molto, ogni millisecondo conta. Tuttavia, creo solo 32 processi e ci vorrà un po 'di tempo. Accadrà solo una volta. Non farà alcuna differenza.

- Quando voglio creare migliaia di thread, allora?

- Non vuoi mai creare migliaia di thread. Tuttavia, su un sistema che sta eseguendo un lavoro che proviene dall'esterno, come un server web che elabora le richieste HTTP; se stai usando un thread per ogni richiesta, creerai molti thread, molti dei quali.

- Node è diverso, però? Destra?

-- Si, esattamente. È qui che Node brilla davvero. Come un thread è molto più leggero di un processo, una chiamata di funzione è molto più leggero di un thread. Il nodo chiama le funzioni, invece di creare thread. Nell'esempio di un server web, ogni richiesta in arrivo provoca una chiamata di funzione.

- Hmm, interessante; ma puoi eseguire solo una funzione alla volta se non stai usando più thread. Come può funzionare quando molte richieste arrivano al server web contemporaneamente?

- Hai perfettamente ragione su come vengono eseguite le funzioni, una alla volta, mai due in parallelo. Voglio dire in un singolo processo, viene eseguito un solo ambito di codice alla volta. L'utilità di pianificazione del sistema operativo non viene a mettere in pausa questa funzione e passa a un'altra, a meno che non interrompa il processo per dare tempo a un altro processo, non a un altro thread nel nostro processo. (2)

- Allora come può un processo gestire 2 richieste alla volta?

- Un processo può gestire decine di migliaia di richieste alla volta purché il nostro sistema disponga di risorse sufficienti (RAM, rete, ecc.). Il modo in cui vengono eseguite queste funzioni è LA DIFFERENZA CHIAVE.

- Hmm, dovrei essere eccitato adesso?

- Forse :) Node esegue un ciclo su una coda. In questa coda ci sono i nostri lavori, cioè le chiamate che abbiamo avviato per elaborare le richieste in arrivo. Il punto più importante qui è il modo in cui progettiamo le nostre funzioni per l'esecuzione. Invece di iniziare a elaborare una richiesta e fare in modo che il chiamante attenda fino al termine del lavoro, terminiamo rapidamente la nostra funzione dopo aver svolto una quantità accettabile di lavoro. Quando arriviamo a un punto in cui dobbiamo aspettare che un altro componente faccia del lavoro e ci restituisca un valore, invece di aspettare quello, finiamo semplicemente la nostra funzione aggiungendo il resto del lavoro alla coda.

- Sembra troppo complesso?

- No no, potrei sembrare complesso; ma il sistema stesso è molto semplice e ha perfettamente senso.

Ora voglio smetterla di citare il dialogo tra questi due sviluppatori e concludere la mia risposta dopo un ultimo rapido esempio di come funzionano queste funzioni.

In questo modo, stiamo facendo ciò che normalmente farebbe OS Scheduler. Mettiamo in pausa il nostro lavoro a un certo punto e lasciamo che altre chiamate di funzione (come altri thread in un ambiente multi-thread) vengano eseguite fino a quando non torniamo di nuovo a turno. Questo è molto meglio che lasciare il lavoro a OS Scheduler che cerca di dare solo il tempo a ogni thread sul sistema. Sappiamo cosa stiamo facendo molto meglio di OS Scheduler e ci si aspetta che ci fermiamo quando dovremmo fermarci.

Di seguito è riportato un semplice esempio in cui apriamo un file e lo leggiamo per lavorare sui dati.

Modo sincrono:

Open File
Repeat This:    
    Read Some
    Do the work

Modo asincrono:

Open File and Do this when it is ready: // Our function returns
    Repeat this:
        Read Some and when it is ready: // Returns again
            Do some work

Come vedi, la nostra funzione chiede al sistema di aprire un file e non attende che venga aperto. Termina da solo fornendo i passaggi successivi dopo che il file è pronto. Quando torniamo, Node esegue altre chiamate di funzione sulla coda. Dopo aver eseguito tutte le funzioni, il ciclo di eventi passa al turno successivo ...

In sintesi, Node ha un paradigma completamente diverso dallo sviluppo multi-threaded; ma questo non vuol dire che manchi di cose. Per un lavoro sincrono (dove possiamo decidere l'ordine e il modo di elaborazione), funziona così come il parallelismo multi-thread. Per un lavoro che proviene dall'esterno come richieste a un server, è semplicemente superiore.


(1) A meno che tu non stia creando librerie in altri linguaggi come C / C ++, nel qual caso non crei ancora thread per dividere i lavori. Per questo tipo di lavoro hai due thread uno dei quali continuerà la comunicazione con Node mentre l'altro fa il lavoro vero e proprio.

(2) In effetti, ogni processo Node ha più thread per gli stessi motivi che ho menzionato nella prima nota a piè di pagina. Tuttavia, non è possibile che 1000 thread eseguano lavori simili. Questi thread aggiuntivi servono per cose come accettare eventi di I / O e gestire la messaggistica tra processi.

AGGIORNAMENTO (in risposta a una buona domanda nei commenti)

@ Marco, grazie per le critiche costruttive. Nel paradigma di Node, non dovresti mai avere funzioni che impiegano troppo tempo per essere elaborate a meno che tutte le altre chiamate nella coda non siano progettate per essere eseguite una dopo l'altra. In caso di compiti computazionalmente costosi, se guardiamo il quadro completo, vediamo che non è una questione di "Dobbiamo usare thread o processi?" ma una domanda di "Come possiamo dividere queste attività in modo ben bilanciato in sotto-attività che possiamo eseguirle in parallelo utilizzando più core della CPU sul sistema?" Supponiamo che elaboreremo 400 file video su un sistema con 8 core. Se vogliamo elaborare un file alla volta, allora abbiamo bisogno di un sistema che elabori parti diverse dello stesso file, nel qual caso, forse, un sistema a processo singolo multi-thread sarà più facile da costruire e ancora più efficiente. Possiamo ancora usare Node per questo eseguendo più processi e passando messaggi tra di loro quando è necessaria la condivisione / comunicazione dello stato. Come ho detto prima, un approccio multi-processo con Node ècosì come un approccio multi-thread in questo tipo di attività; ma non di più. Ancora una volta, come ho detto prima, la situazione in cui Node brilla è quando abbiamo queste attività in ingresso al sistema da più fonti poiché mantenere molte connessioni contemporaneamente è molto più leggero in Node rispetto a un thread per connessione o processo per connessione sistema.

Per quanto riguarda le setTimeout(...,0)chiamate; a volte può essere necessaria una pausa durante un'attività che richiede tempo per consentire alle chiamate in coda di avere la loro parte di elaborazione. Dividere le attività in modi diversi può salvarti da queste; ma ancora, questo non è davvero un trucco, è solo il modo in cui funzionano le code degli eventi. Inoltre, usare process.nextTickper questo scopo è molto meglio poiché quando lo usi setTimeout, sarà necessario calcolare e controllare il tempo trascorso mentre process.nextTickè semplicemente quello che vogliamo veramente: "Ehi compito, torna alla fine della coda, hai usato la tua quota! "


9
Sorprendente! Dannatamente fantastico! Mi è piaciuto il modo in cui hai risposto a questa domanda! :)
Parth Thakkar

48
Certo :) Non riesco davvero a credere che ci siano persone estremamente cattive là fuori che votano per difetto questo articolo di risposta! L'interrogante lo chiama "Dannatamente incredibile!" e un autore di libri mi offre di scrivere sul suo sito web dopo aver visto questo; ma alcuni geni là fuori lo disapprovano. Perché non condividi la tua brillante qualità intellettuale e la commenti invece di votare in modo meschino e subdolo, eh? Perché qualcosa di carino ti disturba così tanto? Perché vuoi impedire che qualcosa di utile raggiunga altre persone che possono davvero trarne beneficio?
hasanyasin

9
Questa non è una risposta completamente giusta. E i compiti computazionalmente costosi, dove non possiamo "terminare rapidamente" la nostra chiamata di funzione? Credo che alcune persone usino alcuni setTimeout(...,0)hack per questo, ma usare un thread separato in questo scenario sarebbe sicuramente meglio?
mpen

3
@hasanyasin Questa è la spiegazione più carina sul nodo che ho trovato finora! :)
Venemo

7
@Mark Generalmente, se è così costoso dal punto di vista computazionale, ci sono opzioni / moduli per i lavoratori di battistrada / processo ... In generale per questo tipo di cose, utilizzo una coda di messaggi e ho processi di lavoro che gestiscono un'attività in un tempo dalla coda e svolgere tale attività. Ciò consente anche il ridimensionamento su più server. In questo senso, Substack ha molti moduli diretti al provisioning e al ridimensionamento che puoi esaminare.
Tracker1

34

(Aggiornamento 2016: i web worker stanno entrando in io.js - un fork di Node.js Node.js v7 - vedi sotto.)

(Aggiornamento 2017: i web worker non accedono a Node.js v7 o v8 - vedi sotto.)

(Aggiornamento 2018: i web worker sono entrando in Node.js Node v10.5.0 - vedi sotto.)

Qualche chiarimento

Dopo aver letto le risposte sopra, vorrei sottolineare che non c'è nulla nei web worker che sia contrario alla filosofia di JavaScript in generale e di Node in particolare per quanto riguarda la concorrenza. (Se ci fosse, non sarebbe nemmeno discusso dal WHATWG, tanto meno implementato nei browser).

Puoi pensare a un web worker come a un microservizio leggero a cui si accede in modo asincrono. Nessuno stato è condiviso. Non esistono problemi di blocco. Non ci sono blocchi. Non è necessaria la sincronizzazione. Proprio come quando usi un servizio RESTful dal tuo programma Node, non ti preoccupi che ora sia "multithread" perché il servizio RESTful non è nello stesso thread del tuo ciclo di eventi. È solo un servizio separato a cui accedi in modo asincrono e questo è ciò che conta.

Lo stesso è con i web worker. È solo un'API per comunicare con codice che viene eseguito in un contesto completamente separato e che si trovi in ​​thread diversi, processi diversi, cgroup, zone, contenitori o macchine diverse è completamente irrilevante, a causa di un'API strettamente asincrona e non bloccante, con tutti i dati passati per valore.

È un dato di fatto che i web worker siano concettualmente perfetti per Node che - come molte persone non sono consapevoli - incidentalmente utilizza i thread in modo piuttosto pesante, e infatti "tutto funziona in parallelo tranne il tuo codice" - vedi:

Ma i web worker non hanno nemmeno bisogno di essere implementati utilizzando i thread. È possibile utilizzare processi, thread verdi o persino servizi RESTful nel cloud, a condizione che venga utilizzata l'API del web worker. L'intera bellezza dell'API di passaggio dei messaggi con semantica chiamata per valore è che l'implementazione sottostante è praticamente irrilevante, poiché i dettagli del modello di concorrenza non verranno esposti.

Un ciclo di eventi a thread singolo è perfetto per le operazioni associate a I / O. Non funziona così bene per le operazioni legate alla CPU, specialmente quelle di lunga durata. Per questo abbiamo bisogno di generare più processi o utilizzare thread. Gestire i processi figli e la comunicazione tra processi in modo portabile può essere abbastanza difficile ed è spesso visto come un eccessivo per compiti semplici, mentre usare i thread significa affrontare blocchi e problemi di sincronizzazione che sono molto difficili da fare bene.

Ciò che è spesso consigliato è di dividere le operazioni di lunga durata legate alla CPU in attività più piccole (qualcosa come l'esempio nella sezione "Risposta originale" della mia risposta a Speed ​​up setInterval ) ma non è sempre pratico e non usa di più più di un core della CPU.

Lo scrivo per chiarire i commenti che sostanzialmente dicevano che i web worker sono stati creati per i browser, non per i server (dimenticando che si può dire praticamente di tutto in JavaScript).

Moduli del nodo

Ci sono pochi moduli che dovrebbero aggiungere Web Worker a Node:

Non ne ho usato nessuno, ma ho due rapide osservazioni che potrebbero essere rilevanti: a marzo 2015, node-webworker è stato aggiornato l'ultima volta 4 anni fa e node-webworker-thread è stato aggiornato l'ultima volta un mese fa. Inoltre vedo nell'esempio dell'utilizzo di node-webworker-thread che puoi usare una funzione invece di un nome di file come argomento per il costruttore Worker che sembra che possa causare problemi sottili se è implementato usando thread che condividono la memoria (a meno che il functions viene utilizzato solo per il suo metodo .toString () ed è altrimenti compilato in un ambiente diverso, nel qual caso potrebbe andare bene - devo esaminarlo più a fondo, condividendo qui le mie osservazioni).

Se c'è qualche altro progetto rilevante che implementa l'API dei web worker in Node, lascia un commento.

Aggiorna 1

Non lo sapevo ancora, al momento della scrittura, ma per inciso un giorno prima che ho scritto questa risposta Web lavoratori sono stati aggiunti alla io.js .

( io.js è un fork di Node.js - vedi: Perché io.js ha deciso di fare il fork di Node.js , un'intervista di InfoWorld con Mikeal Rogers, per maggiori informazioni.)

Non solo dimostra il punto che non c'è nulla nei web worker che sia contrario alla filosofia di JavaScript in generale e di Node in particolare per quanto riguarda la concorrenza, ma può risultare che i web worker siano cittadini di prima classe in JavaScript lato server come io. js (e possibilmente Node.js in futuro) proprio come lo è già in JavaScript lato client in tutti i browser moderni .

Aggiorna 2

Nell'aggiornamento 1 e nel mio tweet mi riferivo alla richiesta pull # 1159 di io.js che ora reindirizza al nodo PR # 1159 che è stato chiuso l'8 luglio e sostituito con il nodo PR # 2133 , che è ancora aperto. Ci sono alcune discussioni in corso sotto quelle richieste pull che possono fornire alcune informazioni più aggiornate sullo stato dei web worker in io.js / Node.js.

Aggiorna 3

Informazioni più recenti - grazie a NiCk Newman per averlo postato nei commenti: Ci sono i lavoratori: commit di implementazione iniziale di Petka Antonov del 6 settembre 2015 che può essere scaricato e provato in questo albero . Vedere i commenti di NiCk Newman per i dettagli.

Aggiorna 4

A maggio 2016 gli ultimi commenti sul PR # 2133 ancora aperto - lavoratori: l'implementazione iniziale risaliva a 3 mesi fa. Il 30 maggio Matheus Moreira mi ha chiesto di pubblicare un aggiornamento a questa risposta nei commenti qui sotto e ha chiesto lo stato attuale di questa funzione nei commenti PR.

Le prime risposte nella discussione di PR erano scettiche, ma in seguito Ben Noordhuis scrisse che "Ottenere questo fuso in una forma o nell'altra è nella mia lista di cose da fare per v7".

Tutti gli altri commenti sembravano confermarlo e da luglio 2016 sembra che Web Workers dovrebbe essere disponibile nella prossima versione di Node , la versione 7.0 che dovrebbe essere rilasciata nell'ottobre 2016 (non necessariamente sotto forma di questo PR esatto).

Grazie a Matheus Moreira per averlo evidenziato nei commenti e rilanciato la discussione su GitHub.

Aggiorna 5

A partire da luglio 2016 ci sono pochi moduli su npm che non erano disponibili prima: per un elenco completo dei moduli pertinenti, cerca npm per lavoratori, web worker, ecc. Se qualcosa in particolare funziona o non funziona per te, pubblica un commento.

Aggiorna 6

A partire da gennaio 2017 è improbabile che i web worker vengano incorporati in Node.js.

La richiesta pull # 2133 lavoratori: l'implementazione iniziale di Petka Antonov dall'8 luglio 2015 è stata finalmente chiusa da Ben Noordhuis l'11 dicembre 2016 che ha commentato che "il supporto multi-threading aggiunge troppe nuove modalità di errore per un vantaggio non sufficiente" e "noi può anche farlo utilizzando mezzi più tradizionali come la memoria condivisa e una serializzazione più efficiente. "

Per ulteriori informazioni, vedere i commenti al PR 2133 su GitHub.

Grazie ancora a Matheus Moreira per averlo segnalato nei commenti.

Aggiorna 6

Sono felice di annunciare che pochi giorni fa, a giugno 2018, i web worker sono apparsi in Node v10.5.0 come funzionalità sperimentale attivata con il --experimental-workerflag.

Per ulteriori informazioni, vedere:

🎉🎉🎉 Finalmente! Posso fare il settimo aggiornamento alla mia risposta Stack Overflow di 3 anni in cui sostengo che il threading a la web worker non è contro la filosofia di Node, solo che questa volta ci siamo finalmente riusciti! 😜👍


1
@NiCkNewman Thanks. Vedo che la richiesta pull originale in io.js ora è chiusa e sostituita con un'altra - con qualche discussione lì nei commenti delle richieste pull su GitHub, forse sarai in grado di trovare alcune informazioni lì. Vedi: Aggiornamento 2 nella mia risposta.
rsp

1
Sì, sembra che abbiano appena risolto l'ultimo problema di libuv. Mi chiedo quando posso mettere le mani sul modulo. Non posso aspettare! Grazie per tenerci aggiornati ~ Modifica: appena inizializzato: github.com/petkaantonov/io.js/commit/… Ecco qua , sta arrivando!
NiCk Newman

1
Sì, è live. (Non ancora implementato ufficialmente) ma puoi scaricare il sorgente qui: github.com/petkaantonov/io.js/tree/… e compilarlo se vuoi provarlo! Lo sto facendo ora ~
NiCk Newman

1
@NiCkNewman Grazie per le nuove informazioni - l'ho aggiunto alla risposta.
rsp

1
Potete aggiornarci sullo stato dell'implementazione di Node.js workers? Gli ultimi commenti in PR # 2133 sono di febbraio; gli sviluppatori apparentemente hanno riscontrato un problema e non ci sono commenti che indichino che sia stato risolto.
Matheus Moreira

8

Vengo dalla vecchia scuola di pensiero in cui usavamo il multi-threading per rendere veloce il software. Negli ultimi 3 anni ho utilizzato Node.js e un grande sostenitore di esso. Come hasanyasin ha spiegato in dettaglio come funziona il nodo e il concetto di funzionalità asincrona. Ma lasciatemi aggiungere alcune cose qui.

Ai vecchi tempi con single core e velocità di clock inferiori abbiamo provato vari modi per far funzionare il software in modo veloce e parallelo. nei giorni DOS usiamo per eseguire un programma alla volta. In Windows abbiamo iniziato a eseguire più applicazioni (processi) insieme. Concetti come preventivo e non preventivo (o cooperativo) dove testati. ora sappiamo che la prevenzione era la risposta per una migliore attività di multielaborazione su computer single core. Sono arrivati ​​i concetti di processi / attività e cambio di contesto. Rispetto al concetto di thread per ridurre ulteriormente l'onere del cambio di contesto del processo. Il filo è stato coniato come alternativa leggera alla generazione di nuovi processi.

Quindi, piaccia o no thread di segnale o non multi-core o single core, i tuoi processi saranno anticipati e il tempo sarà ridotto dal sistema operativo.

Nodejs è un singolo processo e fornisce un meccanismo asincrono. Qui i lavori vengono inviati al SO sottostante per eseguire le attività mentre attendiamo in un ciclo di eventi che l'attività finisca. Una volta ricevuto un segnale verde dal sistema operativo, eseguiamo tutto ciò che dobbiamo fare. Ora in un certo senso questo è multi-tasking cooperativo / non preventivo, quindi non dovremmo mai bloccare il ciclo di eventi per un periodo di tempo molto lungo, altrimenti degraderemo la nostra applicazione molto velocemente.
Quindi, se c'è mai un'attività che si blocca in natura o richiede molto tempo, dovremo estenderla al mondo preventivo del sistema operativo e dei thread. ci sono buoni esempi di questo nella documentazione di libuv . Anche se si legge la documentazione più si scopre che Fileia / O viene gestita nel thread in node.js .

Quindi in primo luogo è tutto nella progettazione del nostro software. In secondo luogo, il cambio di contesto avviene sempre, indipendentemente da ciò che ti dicono. I thread ci sono e sono ancora lì per un motivo, il motivo è che sono più veloci nel passare da un processo all'altro.

Sotto il cofano in node.js è tutto c ++ e thread. E node fornisce il modo c ++ per estendere le sue funzionalità e per accelerare ulteriormente utilizzando thread in cui sono un must, ad esempio, bloccando attività come la lettura da una fonte che scrive in una fonte, analisi di dati di grandi dimensioni e così via.

So che la risposta di hasanyasin è quella accettata, ma per me i thread esisteranno indipendentemente da quello che dici o da come li nascondi dietro gli script, in secondo luogo nessuno rompe le cose in thread solo per la velocità che è principalmente fatto per bloccare le attività. E i fili sono nella spina dorsale di Node.js quindi prima di colpire completamente il multi-threading è corretto. Inoltre i thread sono diversi dai processi e la limitazione di avere processi nodo per core non si applica esattamente al numero di thread, i thread sono come attività secondarie di un processo. infatti i thread non vengono visualizzati nel task manager di Windows o nel comando principale di Linux. ancora una volta pesano meno dei processi


Il codice asincrono non è un'enorme innovazione (in effetti lo abbiamo avuto per decenni) e il multithreading non è una tecnologia deprecata da sostituire. Sono strumenti diversi con compromessi diversi e in effetti possono anche essere combinati abbastanza bene. Ogni volta che esegui node-cluster, in effetti esegui più "thread" (processi in questo caso, ma lo stesso potrebbe essere ottenuto con i thread, ed essere ancora più leggero). Oppure prendi Erlang o Go, che può eseguire migliaia di fili verdi ...
Hejazzman

Penso che il punto principale che ci manca è che il processo nell'ambito del sistema operativo sarà sempre svolto in modo preventivo per garantire l'equità. Anche con più processori puoi avere un'effettiva esecuzione di codice parallelo, ma anche in questo caso avrai la prelazione. Il lavoro asincrono viene svolto anche dal sistema operativo in alcuni casi per un processo.
limplash

4

Non sono sicuro che i webworker siano rilevanti in questo caso, sono tecnologici lato client (eseguiti nel browser), mentre node.js viene eseguito sul server. Le fibre, per quanto ho capito, sono anche bloccanti, cioè sono multitasking volontario, quindi potresti usarle, ma dovresti gestire tu stesso i cambi di contesto tramite yield. I thread potrebbero essere effettivamente ciò di cui hai bisogno, ma non so quanto siano maturi in node.js.


3
solo per tua informazione, i webworker sono stati (parzialmente) adattati su node.js. E sono disponibili come node-workerspacchetto. Dai un'occhiata a questo: github.com/cramforce/node-worker
Parth Thakkar

Buono a sapersi, grazie. Tuttavia, i documenti sono molto scarsi, non ho idea se viene eseguito in un thread separato, processo o semplicemente viene eseguito nello stesso processo e non ho il tempo di approfondire il codice, quindi non ho idea se lo farà lavora per il tuo caso.
lanzz

@ParthThakkar: Quel progetto non è stato toccato in 3 anni (2 quando hai postato) e non ha superato la 0.0.1.
mpen

@Mark: La ragione della mia ignoranza su questo punto è che non sono ancora un programmatore professionista. Diamine, non sono nemmeno in un'università. Sono ancora un compagno di scuola superiore, che continua a leggere di programmazione - oltre a gestire il lavoro scolastico. Quindi, non è neanche lontanamente possibile per me conoscere tutti questi problemi. Ho appena pubblicato quello che sapevo ...
Parth Thakkar

@Mark: Anche se è stato gentile da parte tua sottolinearlo sulla storia del progetto. Queste cose saranno risolte nelle mie future risposte !! :)
Parth Thakkar

3

worker_threadsè stato implementato e spedito dietro una bandiera in node@10.5.0. È ancora un'implementazione iniziale e sono necessari ulteriori sforzi per renderlo più efficiente nelle versioni future. Vale la pena provarlo più tardi node.


2

Secondo le opinioni di molti sviluppatori di Node, una delle parti migliori di Node è in realtà la sua natura a thread singolo. I thread introducono tutta una serie di difficoltà con le risorse condivise che Node evita completamente non facendo altro che IO non bloccante.

Questo non vuol dire che Node sia limitato a un singolo thread. È solo che il metodo per ottenere la concorrenza con thread è diverso da quello che stai cercando. Il modo standard per gestire i thread è con il cluster modulo fornito di serie con Node stesso. È un approccio più semplice ai thread rispetto a gestirli manualmente nel codice.

Per gestire la programmazione asincrona nel codice (come in, evitare piramidi di callback annidate), il componente [Future] nella libreria Fibers è una scelta decente. Ti suggerirei anche di controllare Asyncblock che è basato su Fibre. Le fibre sono utili perché ti consentono di nascondere il callback duplicando lo stack e quindi saltando tra gli stack su un singolo thread quando necessario. Ti risparmia il fastidio di discussioni reali dandoti i vantaggi. Lo svantaggio è che le tracce dello stack possono diventare un po 'strane quando si usano le fibre, ma non sono poi così male.

Se non devi preoccuparti di cose asincrone e sei più interessato a eseguire molte elaborazioni senza blocchi, una semplice chiamata a process.nextTick (callback) ogni tanto è tutto ciò di cui hai bisogno.


beh, il tuo suggerimento - sui cluster - era quello a cui inizialmente pensavo. Ma il problema è il loro sovraccarico: una nuova istanza di v8 deve essere inizializzata ogni volta che viene eseguito il fork di un nuovo processo (~ 30 ms, 10 MB). Quindi, non puoi crearne molti. Questo è preso direttamente dalla documentazione del nodo: questi nodi figlio (sui processi_infanzia) sono ancora istanze completamente nuove di V8. Presupponi almeno 30 ms di avvio e 10 MB di memoria per ogni nuovo nodo. Cioè, non puoi crearne molte migliaia.
Parth Thakkar

1
Questa è esattamente l'idea di cluster. Esegui un worker per core della cpu. Molto probabilmente non è più necessario. Anche le attività intensive della CPU funzioneranno bene con uno stile asincrono. Tuttavia, se hai davvero bisogno di thread in piena regola, dovresti probabilmente considerare di passare completamente a un altro server backend.
genericdave

1

Forse qualche informazione in più sulle attività che stai eseguendo potrebbe aiutare. Perché dovresti (come hai menzionato nel tuo commento alla risposta di genericdave) aver bisogno di crearne molte migliaia? Il modo usuale per fare questo genere di cose in Node è avviare un processo di lavoro (usando fork o qualche altro metodo) che viene sempre eseguito e può essere comunicato usando i messaggi. In altre parole, non avviare un nuovo lavoratore ogni volta che devi eseguire qualsiasi attività tu stia svolgendo, ma invia semplicemente un messaggio al lavoratore già in esecuzione e ottieni una risposta al termine. Onestamente, non vedo nemmeno che l'avvio di molte migliaia di thread effettivi sarebbe molto efficiente, sei ancora limitato dalle tue CPU.

Ora, dopo aver detto tutto questo, ultimamente ho lavorato molto con Hook.io che sembra funzionare molto bene per questo tipo di attività di scaricamento in altri processi, forse può realizzare ciò di cui hai bisogno.

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.