Qual seria melhor para tarefas simultâneas em node.js? Fibras? Trabalhadores da Web? ou tópicos?


111

Tropecei no node.js há algum tempo e gostei muito. Mas logo descobri que faltava muito a capacidade de executar tarefas que exigem muito da CPU. Então, comecei a pesquisar no Google e obtive essas respostas para resolver o problema: Fibers, Webworkers e Threads (thread-a-gogo). Agora, qual deles usar é uma confusão e um deles definitivamente precisa ser usado - afinal, qual é o propósito de ter um servidor que é bom apenas em IO e nada mais? São necessárias sugestões!

ATUALIZAR:

Eu estava pensando em uma maneira tarde; apenas precisando de sugestões sobre isso. Agora, o que pensei foi o seguinte: Vamos fazer alguns tópicos (usando thread_a_gogo ou talvez webworkers). Agora, quando precisarmos de mais deles, podemos criar mais. Mas haverá algum limite para o processo de criação. (não implícito pelo sistema, mas provavelmente devido à sobrecarga). Agora, quando excedemos o limite, podemos bifurcar um novo nó e começar a criar threads sobre ele. Dessa forma, pode continuar até atingirmos algum limite (afinal, os processos também têm uma grande sobrecarga). Quando esse limite é atingido, começamos a enfileirar as tarefas. Sempre que um tópico ficar livre, uma nova tarefa será atribuída a ele. Dessa forma, pode ocorrer sem problemas.

Então, foi nisso que pensei. Essa ideia é boa? Eu sou um pouco novo em todo esse processo e tópicos de tópicos, então não tenho nenhum conhecimento nisso. Por favor, compartilhe suas opiniões.

Obrigado. :)


Observação: os trabalhadores são uma especificação do navegador, não um recurso Javascript.
FredTheWebGuy

Bem, eu vejo isso. Minha pergunta era sobre node.js - código do servidor e não sobre o lado do cliente!
Parth Thakkar

Apenas um esclarecimento - vejo que a pergunta original era sobre Webworkers em NodeJs, o que é impossível - NodeJs usa "Threads". No entanto, existe um módulo NodeJS flutuando que permite a sintaxe WebWorker dentro do tempo de execução NodeJs.
FredTheWebGuy

Respostas:


331

O Node possui um paradigma completamente diferente e, uma vez capturado corretamente, é mais fácil ver essa forma diferente de resolver problemas. Você nunca precisa de vários threads em um aplicativo Node (1) porque você tem uma maneira diferente de fazer a mesma coisa. Você cria vários processos; mas é muito diferente, por exemplo, de como o Prefork mpm do Apache Web Server faz.

Por enquanto, vamos pensar que temos apenas um núcleo de CPU e vamos desenvolver um aplicativo (no jeito do Node) para fazer algum trabalho. Nosso trabalho é processar um arquivo grande executando seu conteúdo byte a byte. A melhor maneira de nosso software é começar o trabalho desde o início do arquivo, acompanhando byte a byte até o final.

- Ei, Hasan, suponho que você seja um novato ou muito antiquado da época do meu avô !!! Por que você não cria alguns tópicos e os torna muito mais rápidos?

- Oh, nós temos apenas um núcleo de CPU.

-- E daí? Cria alguns tópicos cara, torna mais rápido!

-- Não funciona assim. Se eu criar tópicos, o tornarei mais lento. Porque estarei adicionando muita sobrecarga ao sistema para alternar entre os threads, tentando dar a eles uma quantidade justa de tempo, e dentro do meu processo, tentando se comunicar entre esses threads. Além de todos esses fatos, também terei que pensar em como vou dividir um único trabalho em várias partes que podem ser feitas em paralelo.

- Ok ok, vejo que você é pobre. Vamos usar meu computador, ele tem 32 núcleos!

- Nossa, você é demais meu caro amigo, muito obrigado. Eu agradeço!

Então voltamos ao trabalho. Agora temos 32 núcleos de CPU graças ao nosso amigo rico. As regras que devemos obedecer acabam de mudar. Agora queremos utilizar toda essa riqueza que recebemos.

Para usar vários núcleos, precisamos encontrar uma maneira de dividir nosso trabalho em partes que possamos manipular em paralelo. Se não fosse Node, usaríamos threads para isso; 32 threads, um para cada núcleo de CPU. Porém, como temos o Node, criaremos 32 processos de Node.

Threads podem ser uma boa alternativa aos processos do Node, talvez até uma maneira melhor; mas apenas em um tipo específico de trabalho onde o trabalho já está definido e temos total controle sobre como lidar com ele. Fora isso, para todos os outros tipos de problema em que o trabalho vem de fora de uma maneira que não temos controle e queremos responder o mais rápido possível, o jeito de Node é indiscutivelmente superior.

- Ei, Hasan, você ainda está trabalhando single-threaded? O que há de errado com você, cara? Acabei de fornecer o que você queria. Você não tem mais desculpas. Crie threads, faça com que funcionem mais rápido.

- Eu dividi o trabalho em partes e cada processo funcionará em uma dessas partes em paralelo.

- Por que você não cria tópicos?

- Desculpe, não acho que seja utilizável. Você pode levar seu computador se quiser?

- Não ok, estou legal, só não entendo porque você não usa fios?

- Obrigado pelo computador. :) Já dividi o trabalho em partes e crio processos para trabalhar essas peças em paralelo. Todos os núcleos da CPU serão totalmente utilizados. Eu poderia fazer isso com threads em vez de processos; mas o Node tem esse caminho e meu chefe Parth Thakkar quer que eu use o Node.

- Ok, me avise se precisar de outro computador. : p

Se eu criar 33 processos, ao invés de 32, o escalonador do sistema operacional vai pausar um thread, iniciar o outro, pausar após alguns ciclos, iniciar o outro novamente ... Isso é overhead desnecessário. Eu não quero isso. Na verdade, em um sistema com 32 núcleos, eu nem gostaria de criar exatamente 32 processos, 31 podem ser mais agradáveis . Porque não é apenas meu aplicativo que funcionará neste sistema. Deixar um pouco de espaço para outras coisas pode ser bom, especialmente se tivermos 32 quartos.

Acredito que estamos na mesma página agora sobre a utilização total de processadores para tarefas que exigem muito da CPU .

- Hmm, Hasan, me desculpe por zombar um pouco de você. Eu acredito que entendo você melhor agora. Mas ainda há algo para o qual preciso de uma explicação: por que tanto alvoroço sobre a execução de centenas de threads? Eu li em todos os lugares que threads são muito mais rápidos de criar e burros do que processos de bifurcação. Você bifurca processos em vez de threads e acha que é o máximo que obteria com o Node. Então o Node não é apropriado para este tipo de trabalho?

- Não se preocupe, eu também estou bem. Todo mundo diz essas coisas, então acho que estou acostumado a ouvi-las.

-- Assim? O Node não é bom para isso?

- O Node é perfeitamente bom para isso, embora os threads também possam ser bons. Quanto à sobrecarga de criação de thread / processo; nas coisas que você repete muito, cada milissegundo conta. No entanto, eu crio apenas 32 processos e isso vai demorar um pouco. Isso vai acontecer apenas uma vez. Não fará nenhuma diferença.

- Quando eu quero criar milhares de tópicos, então?

- Você nunca quer criar milhares de tópicos. No entanto, em um sistema que está executando um trabalho que vem de fora, como um servidor da Web processando solicitações HTTP; se você estiver usando um thread para cada solicitação, estará criando muitos threads, muitos deles.

- O Node é diferente? Certo?

-- Sim, exatamente. É aqui que o Node realmente brilha. Como um thread é muito mais leve que um processo, uma chamada de função é muito mais leve que um thread. O nó chama funções, em vez de criar threads. No exemplo de um servidor da web, cada solicitação recebida causa uma chamada de função.

-- Hmm interessante; mas você só pode executar uma função ao mesmo tempo se não estiver usando vários threads. Como isso pode funcionar quando muitas solicitações chegam ao servidor da web ao mesmo tempo?

- Você está perfeitamente certo sobre como as funções funcionam, uma de cada vez, nunca duas em paralelo. Quero dizer, em um único processo, apenas um escopo de código está sendo executado por vez. O OS Scheduler não vem e faz uma pausa nesta função e muda para outra, a menos que faça uma pausa no processo para dar tempo a outro processo, não a outro thread em nosso processo. (2)

- Então, como um processo pode lidar com 2 solicitações por vez?

- Um processo pode lidar com dezenas de milhares de solicitações ao mesmo tempo, desde que nosso sistema tenha recursos suficientes (RAM, rede, etc.). Como essas funções funcionam é A DIFERENÇA CHAVE.

- Hmm, devo estar animado agora?

- Talvez :) Node executa um loop em uma fila. Nessa fila estão nossos jobs, ou seja, as chamadas que iniciamos para processar as solicitações recebidas. O ponto mais importante aqui é a maneira como projetamos nossas funções para serem executadas. Em vez de começar a processar uma solicitação e fazer o chamador esperar até terminarmos o trabalho, encerramos rapidamente nossa função depois de realizar uma quantidade de trabalho aceitável. Quando chegamos a um ponto em que precisamos esperar que outro componente faça algum trabalho e nos retorne um valor, em vez de esperar por isso, simplesmente terminamos nossa função adicionando o resto do trabalho à fila.

- Parece muito complexo?

- Não, não, posso parecer complexo; mas o sistema em si é muito simples e faz todo o sentido.

Agora eu quero parar de citar o diálogo entre esses dois desenvolvedores e terminar minha resposta após um último exemplo rápido de como essas funções funcionam.

Desta forma, estamos fazendo o que o OS Scheduler faria normalmente. Pausamos nosso trabalho em algum ponto e deixamos outras chamadas de função (como outras threads em um ambiente multi-thread) serem executadas até chegarmos a nossa vez novamente. Isso é muito melhor do que deixar o trabalho para o OS Scheduler, que tenta dar apenas um tempo para cada thread no sistema. Sabemos o que estamos fazendo muito melhor do que o OS Scheduler e espera-se que paremos quando deveríamos parar.

Abaixo está um exemplo simples onde abrimos um arquivo e o lemos para fazer algum trabalho nos dados.

Forma síncrona:

Open File
Repeat This:    
    Read Some
    Do the work

Forma assíncrona:

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

Como você pode ver, nossa função pede ao sistema para abrir um arquivo e não espera que ele seja aberto. Ele termina fornecendo as próximas etapas após o arquivo estar pronto. Quando retornamos, o Node executa outras chamadas de função na fila. Depois de percorrer todas as funções, o loop de eventos passa para a próxima curva ...

Em resumo, o Node tem um paradigma completamente diferente do desenvolvimento multi-threaded; mas isso não significa que lhe faltem coisas. Para um trabalho síncrono (onde podemos decidir a ordem e a forma de processamento), funciona bem como o paralelismo multi-thread. Para um trabalho que vem de fora, como solicitações para um servidor, ele simplesmente é superior.


(1) A menos que você esteja construindo bibliotecas em outras linguagens como C / C ++, caso em que você ainda não cria threads para dividir tarefas. Para este tipo de trabalho, você tem dois threads, um dos quais continuará a comunicação com o Node enquanto o outro faz o trabalho real.

(2) Na verdade, cada processo do Node tem vários threads pelos mesmos motivos que mencionei na primeira nota de rodapé. No entanto, isso não é como 1000 threads fazendo trabalhos semelhantes. Esses threads extras são para coisas como aceitar eventos de E / S e lidar com mensagens entre processos.

ATUALIZAÇÃO (como resposta a uma boa pergunta nos comentários)

@Mark, obrigado pela crítica construtiva. No paradigma do Node, você nunca deve ter funções que demoram muito para processar, a menos que todas as outras chamadas na fila sejam projetadas para serem executadas uma após a outra. No caso de tarefas computacionalmente caras, se olharmos a imagem completa, vemos que não se trata de uma questão de "Devemos usar threads ou processos?" mas uma questão de "Como podemos dividir essas tarefas de uma maneira bem equilibrada em subtarefas para que possamos executá-las em paralelo, empregando vários núcleos de CPU no sistema?" Digamos que processaremos 400 arquivos de vídeo em um sistema com 8 núcleos. Se quisermos processar um arquivo de cada vez, precisamos de um sistema que processe diferentes partes do mesmo arquivo, caso em que, talvez, um sistema multi-threaded de processo único seja mais fácil de construir e ainda mais eficiente. Ainda podemos usar o Node para isso, executando vários processos e passando mensagens entre eles quando o compartilhamento de estado / comunicação for necessário. Como eu disse antes, uma abordagem multiprocessos com Node ébem como uma abordagem multi-thread neste tipo de tarefas; mas não mais do que isso. Novamente, como eu disse antes, a situação que o Node brilha é quando temos essas tarefas chegando como entrada para o sistema de várias fontes, já que manter muitas conexões simultaneamente é muito mais fácil no Node em comparação com um thread por conexão ou processo por conexão sistema.

Quanto às setTimeout(...,0)ligações; às vezes, pode ser necessário dar uma pausa durante uma tarefa demorada para permitir que as chamadas na fila tenham sua parcela de processamento. Dividir tarefas de maneiras diferentes pode salvá-lo disso; mas ainda assim, isso não é realmente um hack, é apenas a forma como as filas de eventos funcionam. Além disso, usar process.nextTickpara este fim é muito melhor, pois quando você usa setTimeout, o cálculo e a verificação do tempo passado serão necessários enquanto process.nextTické simplesmente o que realmente queremos: "Ei tarefa, volte para o fim da fila, você usou o seu compartilhamento! "


9
Surpreendente! Incrível! Adorei a maneira como você respondeu a essa pergunta! :)
Parth Thakkar

48
Claro :) Eu realmente não posso acreditar que há pessoas extremamente más por aí votando contra este artigo-resposta! Questionador chama de "Incrível!" e um autor de livro me ofereceu escrever em seu site depois de ver isso; mas alguns gênios por aí votam contra ele. Por que você não compartilha sua brilhante qualidade intelectual e comenta sobre ela, em vez de votar malvadamente e sorrateiramente? Por que algo bom te perturba tanto? Por que você deseja evitar que algo útil alcance outras pessoas que podem realmente se beneficiar com isso?
hasanyasin 01 de

9
Esta não é uma resposta completamente justa. E quanto às tarefas computacionalmente caras, nas quais não podemos "encerrar rapidamente" nossa chamada de função? Acredito que algumas pessoas usam alguns setTimeout(...,0)hacks para isso, mas usar um thread separado neste cenário certamente seria melhor?
MPEN

3
@hasanyasin Esta é a melhor explicação sobre o node que encontrei até agora! :)
Venemo

7
@Mark Geralmente, se for tão caro computacionalmente, existem opções / módulos para tread / process workers ... Em geral para esses tipos de coisas, eu uso uma Message Queue e tenho processos de trabalho que lidam com uma tarefa em um tempo da fila e trabalhar nessa tarefa. Isso também permite o dimensionamento para vários servidores. Junto com essas linhas, Substack tem muitos módulos direcionados ao provisionamento e dimensionamento que você pode examinar.
Tracker1

34

(Atualização de 2016: Web workers estão indo para io.js - um fork do Node.js Node.js v7 - veja abaixo.)

(Atualização de 2017: Web workers não vão para o Node.js v7 ou v8 - veja abaixo.)

(Atualização 2018: Web workers estão entrando no Node.js Node v10.5.0 - veja abaixo.)

Algum esclarecimento

Depois de ler as respostas acima, gostaria de salientar que não há nada nos web workers que seja contra a filosofia do JavaScript em geral e do Node em particular em relação à simultaneidade. (Se houvesse, nem seria discutido pelo WHATWG, muito menos implementado nos navegadores).

Você pode pensar em um web worker como um microsserviço leve que é acessado de forma assíncrona. Nenhum estado é compartilhado. Não existem problemas de bloqueio. Não há bloqueio. Não há necessidade de sincronização. Assim como quando você usa um serviço RESTful de seu programa Node, você não se preocupa se agora ele é "multithreaded" porque o serviço RESTful não está no mesmo segmento de seu próprio loop de evento. É apenas um serviço separado que você acessa de forma assíncrona e é isso que importa.

O mesmo acontece com os web workers. É apenas uma API para se comunicar com o código que é executado em um contexto completamente separado e se está em um thread diferente, um processo diferente, um cgroup diferente, uma zona, um contêiner ou uma máquina diferente é completamente irrelevante, por causa de uma API estritamente assíncrona e sem bloqueio, com todos os dados passados ​​por valor.

Na verdade, os web workers são conceitualmente perfeitos para o Node, que - como muitas pessoas não estão cientes - usa encadeamentos bastante intensamente e, na verdade, "tudo funciona em paralelo, exceto seu código" - veja:

Mas os web workers nem precisam ser implementados usando threads. Você pode usar processos, threads verdes ou até mesmo serviços RESTful na nuvem - desde que a API do trabalhador da web seja usada. Toda a beleza da API de passagem de mensagem com semântica de chamada por valor é que a implementação subjacente é praticamente irrelevante, pois os detalhes do modelo de simultaneidade não serão expostos.

Um loop de evento de thread único é perfeito para operações vinculadas a E / S. Não funciona bem para operações vinculadas à CPU, especialmente as de longa duração. Para isso, precisamos gerar mais processos ou usar threads. Gerenciar processos filhos e a comunicação entre processos de uma forma portátil pode ser bastante difícil e muitas vezes é visto como um exagero para tarefas simples, enquanto usar threads significa lidar com bloqueios e problemas de sincronização que são muito difíceis de corrigir.

O que geralmente é recomendado é dividir as operações de longa duração ligadas à CPU em tarefas menores (algo como o exemplo na seção "Resposta original" da minha resposta para Acelerar setInterval ), mas nem sempre é prático e não usa mais de um núcleo de CPU.

Estou escrevendo para esclarecer os comentários que basicamente diziam que os web workers foram criados para navegadores, não servidores (esquecendo que isso pode ser dito sobre praticamente tudo em JavaScript).

Módulos de nó

Existem alguns módulos que devem adicionar Web Workers ao Node:

Não usei nenhum deles, mas tenho duas observações rápidas que podem ser relevantes: em março de 2015, node-webworker foi atualizado pela última vez há 4 anos e node-webworker-threads foi atualizado pela última vez há um mês. Também vejo no exemplo de uso de node-webworker-threads que você pode usar uma função em vez de um nome de arquivo como um argumento para o construtor Worker, o que parece que pode causar problemas sutis se for implementado usando threads que compartilham memória (a menos que funções é usado apenas para seu método .toString () e, de outra forma, é compilado em um ambiente diferente, caso em que pode ser bom - eu tenho que olhar mais a fundo, apenas compartilhando minhas observações aqui).

Se houver algum outro projeto relevante que implemente a API de web workers no Node, deixe um comentário.

Atualização 1

Eu não sabia disso ainda, no momento da escrita, mas por acaso um dia antes eu escrevi esta resposta Web Workers foram adicionados io.js .

( io.js é um fork do Node.js - veja: Por que o io.js decidiu fazer um fork do Node.js , uma entrevista da InfoWorld com Mikeal Rogers, para mais informações.)

Isso não apenas prova que não há nada nos web workers que seja contra a filosofia do JavaScript em geral e do Node em particular em relação à simultaneidade, mas pode resultar em web workers serem cidadãos de primeira classe em JavaScript do lado do servidor como o io. js (e possivelmente Node.js no futuro), assim como já está no JavaScript do lado do cliente em todos os navegadores modernos .

Atualização 2

Na atualização 1 e no meu tweet, eu estava me referindo à solicitação de pull de io.js nº 1159, que agora redireciona para o Nó PR nº 1159 que foi fechado em 8 de julho e substituído pelo Nó PR nº 2133 - que ainda está aberto. Há alguma discussão ocorrendo sob essas solicitações pull que podem fornecer algumas informações mais atualizadas sobre o status dos Web workers em io.js / Node.js.

Atualização 3

Informações mais recentes - obrigado a NiCk Newman por postar nos comentários: Aqui estão os workers: commit de implementação inicial de Petka Antonov de 6 de setembro de 2015 que pode ser baixado e experimentado nesta árvore . Veja os comentários de NiCk Newman para detalhes.

Atualização 4

Em maio de 2016, os últimos comentários sobre o PR # 2133 ainda em aberto - trabalhadores: implementação inicial tinham 3 meses. No dia 30 de maio Matheus Moreira me pediu para postar uma atualização para essa resposta nos comentários abaixo e ele perguntou sobre o status atual desse recurso nos comentários de RP.

As primeiras respostas na discussão de RP foram céticas, mas depois Ben Noordhuis escreveu que "Fazer isso mesclado de uma forma ou de outra está na minha lista de tarefas para a v7".

Todos os outros comentários pareciam concordar com isso e, a partir de julho de 2016, parece que Web Workers deve estar disponível na próxima versão do Node , a versão 7.0, que está planejada para ser lançada em outubro de 2016 (não necessariamente na forma deste PR exato).

Agradecimentos a Matheus Moreira por apontar isso nos comentários e reviver a discussão no GitHub.

Atualização 5

Em julho de 2016, havia alguns módulos no npm que não estavam disponíveis antes - para uma lista completa de módulos relevantes, pesquise npm para workers, web workers etc. Se algo em particular funcionar ou não funcionar para você, poste um Comente.

Atualização 6

A partir de janeiro de 2017 , é improvável que os web workers sejam integrados ao Node.js.

A solicitação pull # 2133 workers: implementação inicial por Petka Antonov de 8 de julho de 2015 foi finalmente encerrada por Ben Noordhuis em 11 de dezembro de 2016, que comentou que "o suporte multi-threading adiciona muitos novos modos de falha para benefício insuficiente" e "nós também pode fazer isso usando meios mais tradicionais, como memória compartilhada e serialização mais eficiente. "

Para obter mais informações, consulte os comentários do PR 2133 no GitHub.

Agradeço mais uma vez a Matheus Moreira por apontar isso nos comentários.

Atualização 6

Tenho o prazer de anunciar que, há poucos dias, em junho de 2018, os web workers apareceram no Node v10.5.0 como um recurso experimental ativado com o --experimental-workersinalizador.

Para obter mais informações, consulte:

🎉🎉🎉 Finalmente! Posso fazer a sétima atualização para minha resposta Stack Overflow de 3 anos, onde eu argumento que threading a la web workers não é contra a filosofia do Node, só que desta vez dizendo que finalmente entendemos! 😜👍


1
@NiCkNewman Obrigado. Vejo que a solicitação de pull original no io.js foi fechada agora e substituída por outra - com alguma discussão nos comentários das solicitações de pull no GitHub, talvez você consiga encontrar algumas informações lá. Veja: Atualização 2 em minha resposta.
rsp

1
Sim, parece que eles acabaram de consertar o último problema de libuv. Eu me pergunto quando poderei colocar minhas mãos no módulo. Não posso esperar! Obrigado por nos manter atualizados ~ Editar: Acabei de inicializar: github.com/petkaantonov/io.js/commit/… Lá vamos nós, está chegando!
NiCk Newman

1
Sim, é ao vivo. (Ainda não implementado oficialmente), mas você pode baixar o código-fonte aqui: github.com/petkaantonov/io.js/tree/… e compilar se quiser testá-lo! Estou fazendo agora ~
NiCk Newman

1
@NiCkNewman Obrigado pela nova informação - adicionei-a à resposta.
rsp

1
Você pode nos atualizar sobre o status da workersimplementação do Node.js. Os comentários mais recentes no PR # 2133 são de fevereiro; os desenvolvedores aparentemente encontraram um problema e não há comentários indicando que ele foi resolvido.
Matheus Moreira

8

Eu venho da velha escola de pensamento onde usamos multi-threading para tornar o software rápido. Nos últimos 3 anos, tenho usado o Node.js e um grande apoiador dele. Como hasanyasin explicou em detalhes como o nó funciona e o conceito de funcionalidade assíncrona. Mas deixe-me acrescentar algumas coisas aqui.

Nos velhos tempos, com núcleos únicos e velocidades de clock menores, tentamos várias maneiras de fazer o software funcionar rápido e em paralelo. nos dias do DOS, usamos para executar um programa por vez. Do que no Windows, começamos a executar vários aplicativos (processos) juntos. Conceitos como preemptivo e não preemptivo (ou cooperativo) foram testados. sabemos agora que preemptiva era a resposta para uma melhor tarefa de multiprocessamento em computadores de núcleo único. Junto vieram os conceitos de processos / tarefas e troca de contexto. Do que o conceito de thread para reduzir ainda mais a carga de alternância de contexto do processo. Thread foi cunhado como alternativa leve para gerar novos processos.

Então, goste ou não sinalize thread ou não seja multi-core ou single core, seus processos serão interrompidos e cortados no tempo pelo SO.

Nodejs é um processo único e fornece mecanismo assíncrono. Aqui, os trabalhos são despachados para o SO subjacente para realizar tarefas enquanto esperamos em um loop de eventos pela conclusão da tarefa. Assim que recebemos um sinal verde do sistema operacional, executamos o que precisamos fazer. De certa forma, esta é uma multitarefa cooperativa / não preemptiva, portanto, nunca devemos bloquear o loop de eventos por um longo período de tempo, caso contrário, degradaremos nosso aplicativo muito rápido.
Portanto, se alguma vez houver uma tarefa que está bloqueando por natureza ou que consome muito tempo, teremos que ramificá-la para o mundo preemptivo do SO e threads. há bons exemplos disso na documentação do libuv . Além disso, se você ler a documentação mais você achar que FileI / O é tratado em tópicos em node.js .

Em primeiro lugar, está tudo no design do nosso software. Em segundo lugar, a troca de contexto está sempre acontecendo, não importa o que eles digam a você. Thread estão lá e ainda estão lá por um motivo, o motivo é que eles são mais rápidos para alternar entre os processos.

Sob o capô em node.js é todo c ++ e threads. E o node fornece uma maneira c ++ de estender sua funcionalidade e acelerar ainda mais o uso de threads onde eles são obrigatórios, ou seja, tarefas de bloqueio como leitura de uma fonte, gravação em uma fonte, grande análise de dados e assim por diante.

Eu sei que a resposta hasanyasin é a mais aceita, mas para mim os threads existirão não importa o que você diga ou como você os esconda atrás dos scripts. Em segundo lugar, ninguém apenas quebra as coisas em threads apenas para velocidade, é feito principalmente para bloquear tarefas. E os threads estão na espinha dorsal do Node.js, então antes de atacar completamente o multi-threading está correto. Além disso, os threads são diferentes dos processos e a limitação de ter processos de nó por núcleo não se aplica exatamente ao número de threads, os threads são como subtarefas de um processo. na verdade, os threads não aparecerão no gerenciador de tarefas do Windows ou no comando top do Linux. mais uma vez, eles têm menos peso do que processos


O código assíncrono não é uma grande inovação (na verdade, já o temos há décadas) e o multithreading não é uma tecnologia obsoleta a ser substituída. São ferramentas diferentes, com vantagens e desvantagens diferentes e, na verdade, podem até ser combinadas muito bem. Toda vez que você executa o node-cluster, você de fato executa vários "threads" (processos neste caso, mas o mesmo pode ser alcançado com threads e ser ainda mais leve). Ou pegue Erlang ou Go, que pode executar milhares de fios verdes ...
Hejazzman

Acho que o principal ponto que está faltando é que o processo no sistema operacional sempre será feito de forma preventiva para oferecer justiça. Além disso, com vários processadores, você pode ter execução real de código paralelo, mas mesmo assim você terá preempção. O trabalho assíncrono também é realizado pelo SO em alguns dos processos.
limplash de

4

Não tenho certeza se os webworkers são relevantes neste caso, eles são técnicos do lado do cliente (executados no navegador), enquanto o node.js é executado no servidor. As fibras, tanto quanto eu entendo, também são bloqueadoras, ou seja, são multitarefas voluntárias, então você pode usá-las, mas deve gerenciar as mudanças de contexto por meio de yield. Threads podem ser realmente o que você precisa, mas não sei o quão maduros eles são em node.js.


3
apenas para sua informação, os webworkers foram (parcialmente) adaptados no node.js. E estão disponíveis como node-workerspacote. Dê uma olhada nisso: github.com/cramforce/node-worker
Parth Thakkar

Bom saber, obrigado. No entanto, os documentos são muito escassos, não tenho ideia se ele é executado em um thread ou processo separado ou simplesmente é executado no mesmo processo, e não tenho tempo para mergulhar no código, então não tenho ideia se será trabalhar para o seu caso.
lanzz

@ParthThakkar: Esse projeto não é tocado há 3 anos (2 quando você postou) e não passou do 0.0.1.
mpen

@Mark: O motivo da minha ignorância sobre isso é que ainda não sou um programador profissional. Caramba, eu nem estou em uma universidade. Ainda sou bolsista do Ensino Médio, que continua lendo sobre programação - além de gerenciar os trabalhos escolares. Portanto, não é remotamente possível para mim ter conhecimento sobre todas essas questões. Acabei de postar o que sabia ...
Parth Thakkar

@Mark: Embora tenha sido legal da sua parte apontar isso sobre a história do projeto. Essas coisas serão tratadas em minhas respostas futuras !! :)
Parth Thakkar

3

worker_threadsfoi implementado e enviado com uma bandeira em node@10.5.0. Ainda é uma implementação inicial e mais esforços são necessários para torná-la mais eficiente em versões futuras. Vale a pena tentar no último node.


2

Na opinião de muitos desenvolvedores do Node, uma das melhores partes do Node é, na verdade, sua natureza de thread único. Threads apresentam uma série de dificuldades com recursos compartilhados que o Node evita completamente fazendo nada além de E / S sem bloqueio.

Isso não quer dizer que o Node esteja limitado a um único thread. Acontece que o método para obter simultaneidade encadeada é diferente do que você está procurando. A maneira padrão de lidar com threads é com o módulo de cluster que vem com o próprio Node. É uma abordagem mais simples para threads do que lidar manualmente com eles em seu código.

Para lidar com programação assíncrona em seu código (como em evitar pirâmides de retorno de chamada aninhadas), o componente [Future] na biblioteca Fibers é uma escolha decente. Também sugiro que você uma olhada no Asyncblock, que é baseado em fibras. As fibras são boas porque permitem que você oculte o retorno de chamada duplicando a pilha e, em seguida, saltando entre as pilhas em um único thread, conforme necessário. Economiza o incômodo de tópicos reais, ao mesmo tempo que oferece os benefícios. A desvantagem é que os rastreamentos de pilha podem ficar um pouco estranhos ao usar o Fibers, mas não são tão ruins.

Se você não precisa se preocupar com coisas assíncronas e está mais apenas interessado em fazer muito processamento sem bloquear, uma simples chamada para process.nextTick (callback) de vez em quando é tudo que você precisa.


bem, sua sugestão - sobre clusters - foi o que pensei inicialmente. Mas o problema com isso é a sobrecarga - uma nova instância do v8 deve ser inicializada toda vez que um novo processo é bifurcado (~ 30 ms, 10 MB). Então, você não pode criar muitos deles. Isso é obtido diretamente dos documentos do nó: Esses nós filhos (sobre child_processes) ainda são instâncias totalmente novas do V8. Suponha que pelo menos 30 ms de inicialização e 10 MB de memória para cada novo nó. Ou seja, você não pode criar muitos milhares deles.
Parth Thakkar

1
Essa é exatamente a ideia de cluster. Você executa um trabalhador por núcleo de CPU. Mais provavelmente é desnecessário. Mesmo as tarefas com uso intensivo de CPU funcionarão bem com um estilo assíncrono. No entanto, se você realmente precisa de threads totalmente desenvolvidos, provavelmente deve considerar a mudança para outro back-end de servidor inteiramente.
genericdave

1

Talvez mais algumas informações sobre quais tarefas você está realizando ajudem. Por que você precisa (como você mencionou em seu comentário à resposta do genericdave) precisa criar muitos milhares deles? A maneira usual de fazer esse tipo de coisa no Node é iniciar um processo de trabalho (usando fork ou algum outro método) que sempre é executado e pode ser comunicado por meio de mensagens. Em outras palavras, não inicie um novo trabalhador cada vez que precisar realizar qualquer tarefa que esteja fazendo, mas simplesmente envie uma mensagem para o trabalhador que já está em execução e obtenha uma resposta quando terminar. Honestamente, não consigo ver que iniciar muitos milhares de threads reais também seria muito eficiente, você ainda está limitado por suas CPUs.

Agora, depois de dizer tudo isso, tenho feito muito trabalho com o Hook.io ultimamente, que parece funcionar muito bem para esse tipo de tarefas de descarregamento em outros processos, talvez ele possa realizar o que você precisa.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.