Quali sono gli svantaggi di creare un'implementazione runtime JavaScript multi-thread? [chiuso]

51

Ho lavorato a un'implementazione di runtime JavaScript multi-threaded per la scorsa settimana. Ho un proof of concept realizzato in C ++ usando JavaScriptCore e boost.

L'architettura è semplice: quando il runtime termina la valutazione dello script principale che avvia e si unisce a un pool di thread, che inizia a raccogliere attività da una coda di priorità condivisa, se due task tentano di accedere a una variabile contemporaneamente viene contrassegnato come atomico e contendone l'accesso.

IlproblemaèchequandomostroquestodisegnoaunprogrammatoreJavaScriptottengounfeedbackestremamentenegativoenonhoideadelperché.Ancheinprivato,tuttidiconocheJavaScriptèpensatoperessereathreadsingolo,chelelibrerieesistentidovrebberoessereriscritteecheigremlinsgenererannoemangerannoogniessereviventesecontinuoalavoraresuquesto.

Originariamenteavevounaimplementazionedicoroutinenativa(usandoicontestidiboost),mahodovutoabbandonarla(JavaScriptCoreèpedanteriguardoallostack),enonvolevorischiarelaloroiraquindihodecisodinonmenzionarloesso.

Chenepensi?JavaScriptèpensatoperessereathreadsingoloedovrebbeesserelasciatoinpace?Perchétuttisonocontrariall'ideadiunruntimeJavaScriptsimultaneo?

Modifica:ilprogettoèorain GitHub , sperimentalo tu stesso e fammi sapere cosa ne pensi.

Di seguito è riportata un'immagine di promesse in esecuzione su tutti i core della CPU in parallelo senza conflitti:

    
posta voodooattack 12.04.2016 - 06:31
fonte

8 risposte

70

1) Il multithreading è estremamente difficile e sfortunatamente il modo in cui hai presentato questa idea fino ad ora ti sta sottovalutando severamente quanto sia difficile.

Al momento, sembra che tu stia semplicemente "aggiungendo discussioni" alla lingua e ti preoccupi di come renderlo corretto e performante in seguito. In particolare:

if two tasks try to access a variable concurrently it gets marked atomic and they contend for access.
...
I agree that atomic variables won't solve everything, but working on a solution for the synchronisation problem is my next goal.

L'aggiunta di thread a Javascript senza una "soluzione per il problema di sincronizzazione" sarebbe come aggiungere numeri interi a Javascript senza una "soluzione per il problema di aggiunta". È così fondamentale per la natura del problema che non c'è praticamente nessun punto di discutere se il multithreading meriti di essere aggiunto senza una soluzione specifica in mente, indipendentemente da quanto potremmo volerlo.

Inoltre, rendere tutte le variabili atomiche è il tipo di cosa che può far sì che un programma multithread esegua peggio rispetto alla sua controparte monofore, il che rende ancora più importante testare effettivamente le prestazioni su programmi più realistici e vedi se stai guadagnando qualcosa o no.

Inoltre, non è chiaro per me se stai cercando di mantenere i thread nascosti dal programmatore node.js o se hai intenzione di esporli ad un certo punto, facendo effettivamente un nuovo dialetto di Javascript per la programmazione multithread. Entrambe le opzioni sono potenzialmente interessanti, ma sembra che tu non abbia ancora deciso quale obiettivo stai ancora cercando.

Quindi, al momento, stai chiedendo ai programmatori di prendere in considerazione il passaggio da un ambiente singletto a un nuovissimo ambiente multithreading che non ha alcuna soluzione per il problema di sincronizzazione e nessuna evidenza migliora le prestazioni del mondo reale e apparentemente nessun piano per la risoluzione questi problemi.

Questo è probabilmente il motivo per cui le persone non ti prendono sul serio.

2) La semplicità e la robustezza del loop di eventi singoli è un vantaggio enorme .

I programmatori di Javascript sanno che la lingua Javascript è "sicura" dalle condizioni di gara e da altri bug estremamente insidiosi che affliggono tutta la programmazione realmente multithread. Il fatto che abbiano bisogno di argomenti forti per convincerli a rinunciare a tale sicurezza non li rende di mentalità chiusa, li rende responsabili.

A meno che tu non sia in grado di mantenere tale sicurezza, chiunque potrebbe voler passare a un nodo con multithreading sarebbe probabilmente meglio passare a una lingua come Go progettata per le applicazioni multithread.

3) Javascript supporta già "thread in background" (WebWorkers) e programmazione asincrona senza esposizione diretta della gestione dei thread al programmatore.

Queste funzionalità risolvono già molti dei casi d'uso comuni che riguardano i programmatori Javascript nel mondo reale, senza rinunciare alla sicurezza del singolo loop eventi.

Hai in mente casi d'uso specifici che queste funzionalità non risolvono e che i programmatori Javascript vogliono una soluzione? Se è così, sarebbe una buona idea presentare il tuo node.js multithread nel contesto di quel caso d'uso specifico.

P.S. Cosa potrebbe convincere me a provare a passare a un'implementazione node.js multithread?

Scrivi un programma non banale in Javascript / node.js che pensi possa trarre beneficio dal vero multithreading. Eseguire test delle prestazioni su questo programma di esempio nel nodo normale e nel nodo con multithreading. Dimostrami che la tua versione migliora le prestazioni di runtime, la reattività e l'utilizzo di più core in misura significativa, senza introdurre bug o instabilità.

Dopo averlo fatto, penso che vedrai le persone molto più interessate a questa idea.

    
risposta data 12.04.2016 - 11:07
fonte
16

Indovina qui per dimostrare un problema nel tuo approccio. Non riesco a metterlo alla prova dell'implementazione reale in quanto non esiste alcun collegamento da nessuna parte ...

Direi che è perché gli invarianti non sono sempre espressi dal valore di una variabile, e 'una variabile' non è sufficiente per essere l'ambito di un blocco nel caso generale. Ad esempio, immagina di avere un invariant che a+b = 0 (il saldo di una banca con due account). Le due funzioni seguenti assicurano che l'invariante sia sempre tenuto alla fine di ogni funzione (l'unità di esecuzione in JS a thread singolo).

function withdraw(v) {
  a -= v;
  b += v;
}
function deposit(v) {
  b -= v;
  a += v;
}

Ora, nel tuo mondo multithreading, cosa succede quando due thread eseguono withdraw e deposit allo stesso tempo? Grazie, Murphy ...

(Potresti avere un codice che tratta + = e - = specialmente, ma questo non è d'aiuto. Ad un certo punto, avrai uno stato locale in una funzione, e senza alcun modo di "bloccare" due variabili allo stesso tempo la tua invariante sarà violata.)

EDIT: se il tuo codice è semanticamente equivalente al codice Go al link , il mio commento è preciso; -)

    
risposta data 12.04.2016 - 09:43
fonte
15

Un decennio fa Brendan Eich (l'inventore di JavaScript) ha scritto un saggio chiamato Thread Suck , che è sicuramente uno dei pochi documenti canonici della mitologia del design di JavaScript.

Se è corretto è un'altra domanda, ma penso che abbia avuto una grande influenza su come la comunità JavaScript pensa alla concorrenza.

    
risposta data 12.04.2016 - 08:20
fonte
9

L'accesso atomico non si traduce in un comportamento thread-safe.

Un esempio è quando una struttura di dati globale deve essere invalida durante un aggiornamento come rimodellare una hashmap (quando si aggiunge una proprietà ad un oggetto per esempio) o ordinare un array globale. Durante questo periodo non è possibile consentire ad altri thread di accedere alla variabile. Ciò significa fondamentalmente che è necessario rilevare l'intero ciclo di lettura-aggiornamento-scrittura e bloccarlo. Se l'aggiornamento non è banale, finirà con l'interruzione del territorio problematico.

Javascript è stato single threaded e sandboxed dall'inizio e tutto il codice è stato scritto pensando a questi presupposti.

Questo ha un grande vantaggio per quanto riguarda i contesti isolati e consente di eseguire 2 contesti separati in thread diversi. Significa anche che le persone che scrivono javascript non hanno bisogno di sapere come affrontare le condizioni di gara e vari altri pitfals multi-thread.

    
risposta data 12.04.2016 - 11:16
fonte
6

Il tuo approccio migliorerà significativamente le prestazioni?

In dubbio. Hai davvero bisogno di provarlo.

Il tuo approccio renderà più semplice / più veloce scrivere codice?

Sicuramente no, il codice multithreading è molte volte più difficile da ottenere rispetto al codice a thread singolo.

Il tuo approccio sarà più solido?

I deadlock, le condizioni di gara, ecc. sono un incubo da risolvere.

    
risposta data 12.04.2016 - 08:14
fonte
2

La tua implementazione non consiste solo nell'introdurre la concorrenza, ma piuttosto nell'introdurre un modo specifico per implementare la concorrenza e la concorrenza in base allo stato mutabile condiviso. Nel corso della storia le persone hanno usato questo tipo di concorrenza e questo ha portato a molti tipi di problemi. Naturalmente è possibile creare programmi semplici che funzionano perfettamente con l'utilizzo della concorrenza mutevole condivisa, ma il vero test di qualsiasi meccanismo non è quello che può fare, ma può ridimensionarsi man mano che il programma diventa complesso e sempre più funzioni vengono aggiunte al programma. Ricorda che il software non è una cosa statica che tu costruisci una volta e che hai finito, piuttosto si evolve nel tempo e se qualche meccanismo o concetto non può far fronte all'evoluzione del software allora porterà solo a nuovi problemi e questo è esattamente quale storia ci ha insegnato sulla concomitanza condivisa di memoria mutevole.

Puoi guardare altri modelli di concorrenza (ad es. il passaggio di messaggi) per aiutarti a capire che tipo di vantaggi forniscono quei modelli.

    
risposta data 12.04.2016 - 07:54
fonte
1

Questo è necessario. La mancanza di un meccanismo di concorrenza di basso livello nel nodo js limita le sue applicazioni in campi come matematica e bioinformatica, ecc ... Inoltre, la concorrenza con i thread non è necessariamente in conflitto con il modello di concurrency predefinito utilizzato nel nodo. Ci sono semantica ben nota per il threading in un ambiente con un ciclo di eventi principale, come ui frameworks (e nodejs), e sono decisamente eccessivamente complessi per la maggior parte delle situazioni che hanno ancora usi validi.

Certo, la tua app web media non richiede thread, ma prova a fare qualcosa di un po 'meno convenzionale, e la mancanza di un primitivo di concorrenza a basso livello ti porterà rapidamente a qualcos'altro che lo offre.

    
risposta data 12.04.2016 - 09:17
fonte
0

Credo davvero che sia perché è un'idea diversa e potente. Stai andando contro i sistemi di credenze. La roba diventa accettata o popolare attraverso gli effetti della rete non sulla base del merito. Inoltre nessuno vuole adattarsi a un nuovo stack. Le persone rifiutano automaticamente le cose che sono troppo diverse.

Se riesci a trovare un modo per trasformarlo in un normale modulo npm che suona improbabile, potresti far sì che alcune persone lo usino.

    
risposta data 12.04.2016 - 07:41
fonte

Leggi altre domande sui tag