Quais são os inconvenientes de fazer uma implementação de tempo de execução JavaScript multi-thread? [fechadas]

51

Eu tenho trabalhado em uma implementação de tempo de execução JavaScript multi-thread para a semana passada. Eu tenho uma prova de conceito feita em C ++ usando JavaScriptCore e boost.

A arquitetura é simples: quando o tempo de execução termina de avaliar o script principal, ele inicia e une um conjunto de encadeamentos, que começa a selecionar tarefas de uma fila de prioridade compartilhada, se duas tarefas tentarem acessar uma variável simultaneamente, ela fica marcada como atômica e disputar o acesso.

OproblemaéquequandomostroessedesignparaumprogramadordeJavaScript,receboumfeedbackextremamentenegativo,enãofaçoideiadomotivo.Mesmoemparticular,todosdizemqueoJavaScriptdevesersinglethreaded,queasbibliotecasexistentesprecisariamserreescritas,equeosgremlinsirãogerarecomertodososseresvivosseeucontinuartrabalhandonisso.

Euoriginalmentetinhaumaimplementaçãodeco-rotinanativa(usandocontextosboost)também,maseutivequeabandoná-la(JavaScriptCoreépedantesobreapilha),eeunãoqueriaarriscarsuairaentãodecidinãomencionarisso.

Oquevocêacha?JavaScriptdevesersinglethreaded,edeveserdeixadosozinho?PorquetodosestãocontraaideiadeumtempodeexecuçãoJavaScriptsimultâneo?

Editar:oprojetoestáagoraem GitHub , experimente você mesmo e deixe-me saber o que você pensa.

A seguir, uma imagem de promessas sendo executadas em todos os núcleos da CPU em paralelo, sem contenção:

    
por voodooattack 12.04.2016 / 06:31
fonte

8 respostas

70

1) O multithreading é extremamente difícil e, infelizmente, a maneira como você apresentou essa idéia até agora implica que você está subestimando seriamente o quanto é difícil.

No momento, parece que você está simplesmente "adicionando tópicos" à linguagem e se preocupando em como torná-la correta e com desempenho posterior. Em particular:

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.

Adicionar threads ao Javascript sem uma "solução para o problema de sincronização" seria como adicionar inteiros ao Javascript sem uma "solução para o problema de adição". É tão fundamental para a natureza do problema que basicamente não adianta discutir se o multithreading vale a pena ser adicionado sem uma solução específica em mente, não importa o quanto queiramos.

Além disso, tornar todas as variáveis atômicas é o tipo de coisa que provavelmente faz com que um programa multithread execute um desempenho pior do que sua contraparte singlethreaded, o que torna ainda mais importante testar o desempenho em programas mais realistas e veja se você está ganhando alguma coisa ou não.

Também não está claro para mim se você está tentando manter os threads ocultos do programador node.js ou se planeja expô-los em algum momento, efetivamente criando um novo dialeto de Javascript para programação multithread. Ambas as opções são potencialmente interessantes, mas parece que você nem sequer decidiu qual delas você está mirando ainda.

Então, no momento, você está pedindo aos programadores que considerem a mudança de um ambiente singlethreaded para um novo ambiente multiencadeado que não tenha solução para o problema de sincronização e nenhuma evidência que melhore o desempenho no mundo real e aparentemente nenhum plano para resolver essas questões.

É provavelmente por isso que as pessoas não te levam a sério.

2) A simplicidade e robustez do loop único evento é uma vantagem enorme .

Programadores em Javascript sabem que a linguagem Javascript é "segura" de condições de corrida e outros bugs extremamente insidiosos que afetam toda a programação genuinamente multithread. O fato de que eles precisam de argumentos strongs para convencê-los a desistir dessa segurança não os torna de mente fechada, isso os torna responsáveis.

A menos que você possa, de alguma forma, manter essa segurança, qualquer pessoa que queira mudar para um node.js multithread seria provavelmente melhor mudar para um idioma como o Go, projetado para aplicações multithreaded.

3) O Javascript já suporta "threads de segundo plano" (WebWorkers) e programação assíncrona sem expor diretamente o gerenciamento de threads ao programador.

Esses recursos já resolvem muitos casos de uso comum que afetam os programadores de JavaScript no mundo real, sem abrir mão da segurança do loop de evento único.

Você tem algum caso de uso específico em mente que esses recursos não resolvem e que os programadores de JavaScript querem uma solução? Em caso afirmativo, seria uma boa ideia apresentar seu node.js multithread no contexto desse caso de uso específico.

P.S. O que convenceria mim a tentar mudar para uma implementação node.js multithread?

Escreva um programa não-trivial em Javascript / node.js que você acha que se beneficiaria com multithreading genuíno. Faça testes de desempenho neste programa de amostra no nó normal e no nó multithread. Mostre-me que sua versão melhora o desempenho em tempo de execução, a capacidade de resposta e o uso de vários núcleos em um nível significativo, sem apresentar nenhum erro ou instabilidade.

Depois de fazer isso, acho que você verá as pessoas muito mais interessadas nessa ideia.

    
por 12.04.2016 / 11:07
fonte
16

Apenas adivinhando aqui para demonstrar um problema em sua abordagem. Eu não posso testá-lo contra a implementação real, pois não há link em lugar nenhum ...

Eu diria que é porque os invariantes nem sempre são expressos pelo valor de uma variável, e 'uma variável' não é suficiente para ser o escopo de um bloqueio no caso geral. Por exemplo, imagine que temos uma invariante que a+b = 0 (saldo de um banco com duas contas). As duas funções abaixo garantem que a invariante seja sempre mantida no final de cada função (a unidade de execução em JS de encadeamento único).

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

Agora, no seu mundo multithread, o que acontece quando dois threads executam withdraw e deposit ao mesmo tempo? Obrigado, Murphy ...

(Você pode ter um código que trate + = e - = especialmente, mas isso não ajuda. Em algum momento, você terá o estado local em uma função e não terá como 'bloquear' duas variáveis ao mesmo tempo seu invariante será violado.)

EDIT: Se o seu código é semanticamente equivalente ao Go code no link , meu comentário é correto; -)

    
por 12.04.2016 / 09:43
fonte
15

Uma década ou mais atrás, Brendan Eich (o inventor do JavaScript) escreveu um ensaio chamado Threads Suck , que é definitivamente um dos poucos documentos canônicos da mitologia de design do JavaScript.

Se isso está correto é outra pergunta, mas acho que teve uma grande influência em como a comunidade JavaScript pensa sobre a simultaneidade.

    
por 12.04.2016 / 08:20
fonte
9

O acesso atômico não se traduz em comportamento thread-safe.

Um exemplo é quando uma estrutura de dados global precisa ser inválida durante uma atualização, como refazer um hashmap (ao adicionar uma propriedade a um objeto, por exemplo) ou classificar um array global. Durante esse tempo, você não pode permitir que nenhum outro thread acesse a variável. Isso basicamente significa que você precisa detectar todos os ciclos de leitura-atualização-gravação e bloquear isso. Se a atualização não for trivial, acabará por parar o território do problema.

O Javascript tem sido segmentado em um único local e colocado em sandbox desde o início e todo o código é escrito com essas suposições em mente.

Isso tem uma grande vantagem em relação a contextos isolados e permite que dois contextos separados sejam executados em diferentes threads. Eu também quero dizer que as pessoas que escrevem javascript não precisam saber como lidar com as condições de corrida e vários outros pitfals multi-thread.

    
por 12.04.2016 / 11:16
fonte
6

A sua abordagem vai melhorar significativamente o desempenho?

Duvidoso. Você realmente precisa provar isso.

A sua abordagem vai tornar mais fácil / rápido escrever código?

Definitivamente, o código multithread é muitas vezes mais difícil de acertar do que o código single-threaded.

A sua abordagem será mais robusta?

Deadlocks, condições de corrida, etc. são um pesadelo para corrigir.

    
por 12.04.2016 / 08:14
fonte
2

Sua implementação não é apenas sobre a introdução de simultaneidade, mas sobre a introdução de uma maneira específica de implementar a simultaneidade, ou seja, a simultaneidade por estado mutável compartilhado. Ao longo da história, as pessoas usaram esse tipo de concorrência e isso levou a muitos tipos de problemas. Claro que você pode criar programas simples que funcionam perfeitamente com o uso de simultaneidade de estado mutável compartilhado, mas o teste real de qualquer mecanismo não é o que ele pode fazer, mas pode ser dimensionado conforme o programa se torna complexo e mais recursos são adicionados ao programa. Lembre-se de software não é uma coisa estática que você constrói uma vez e é feito com ele, em vez disso, continua evoluindo ao longo do tempo e se qualquer mecanismo ou conceito não pode lidar com a evolução do software, então só levará a novos problemas e isso é exatamente o que a história nos ensinou sobre a simultaneidade da memória mutável compartilhada.

Você pode ver outros modelos de simultaneidade (ex: message passing) para ajudá-lo a descobrir que tipo de benefícios esses modelos oferecem.

    
por 12.04.2016 / 07:54
fonte
1

Isso é necessário. A falta de um mecanismo de concorrência de baixo nível no nó js limita suas aplicações em campos como matemática e bioinformática, etc ... Além disso, a simultaneidade com os encadeamentos não necessariamente conflita com o modelo de concor- dência padrão usado no nó. Existem semânticas bem conhecidas para encadeamento em um ambiente com um loop de eventos principal, como frameworks ui (e nodejs), e como elas são definitivamente excessivamente complexas para a maioria das situações, elas ainda têm usos válidos.

Claro, seu aplicativo da web médio não exigirá tópicos, mas tente fazer algo um pouco menos convencional, e a falta de um primitivo de simultaneidade de baixo nível de som rapidamente o levará a algo que o ofereça.

    
por 12.04.2016 / 09:17
fonte
0

Eu realmente acredito que é porque é uma ideia diferente e poderosa. Você está indo contra os sistemas de crenças. Coisas torna-se aceito ou popular através da rede afeta não com base no mérito. Também ninguém quer se adaptar a uma nova pilha. As pessoas rejeitam automaticamente coisas que são muito diferentes.

Se você puder criar uma forma de torná-lo um módulo npm comum, o que parece improvável, você pode fazer com que algumas pessoas o usem.

    
por 12.04.2016 / 07:41
fonte