Pagina inicial » Codificação » Introdução à memória compartilhada em JavaScript

    Introdução à memória compartilhada em JavaScript

    Memoria compartilhada é um recurso avançado do JavaScript, que os encadeamentos (partes executadas simultaneamente de um processo) podem aproveitar. Compartilhando os meios de memória não tendo o problema de passar dados atualizados entre os tópicos e todos os threads podem acessar e atualizar os mesmos dados na memória compartilhada.

    Isso não soa adorável? Bem, quase. Neste post, vamos ver como usar a memória compartilhada em JavaScript e como decidir se é isso que você realmente quer fazer.

    Vantagens e desvantagens da memória compartilhada

    Nós usamos trabalhadores da web para criar tópicos em JavaScript. A API Web Workers nos permite criar encadeamentos de trabalho que podem ser usados ​​para executar código em segundo plano para que o thread principal esteja livre para continuar sua execução, possivelmente processando eventos de UI, garantindo que nenhum congelamento de UI.

    Tópicos de trabalho executar simultaneamente com o thread principal e uns aos outros. Essa execução simultânea de diferentes partes de uma tarefa economiza tempo. Você termina mais rápido, mas também tem seu próprio conjunto de problemas.

    Certificando-se de que cada segmento Obtém os recursos necessários e se comunica uns com os outros em tempo hábil é uma tarefa em si, onde um acidente pode resultar em um resultado surpreendente. Ou se um thread está mudando dados e outro está lendo ao mesmo tempo, o que você acha que o outro segmento vai ver? Os dados atualizados ou antigos?

    No entanto, os web workers não são tão fáceis de estragar. Durante a comunicação através do uso de mensagens, os dados que enviam um ao outro são não original, mas uma cópia, ou seja, eles não compartilhar os mesmos dados. Eles passar cópias de dados entre si quando necessário.

    Mas compartilhar é cuidar e vários segmentos também podem precisar examinar os mesmos dados ao mesmo tempo e alterá-los. assim, banir a partilha é um grande não-não. É aqui que o SharedArrayBuffer objeto entra em cena. Isso nos deixará compartilhar dados binários entre vários segmentos.

    o SharedArrayBuffer objeto

    Em vez de passar as cópias de dados entre os threads, nós passar cópias do SharedArrayBuffer objeto. UMA SharedArrayBuffer objeto aponta para a memória onde os dados são salvos.

    Então, mesmo quando as cópias de SharedArrayBuffer são passados ​​entre threads, eles todos ainda apontarão para a mesma memória onde os dados originais são salvos. Os fios, assim, podem visualizar e atualizar os dados nessa mesma memória.

    Trabalhadores da Web sem memoria compartilhada

    Para ver como um trabalhador da Web trabalha sem usar a memória compartilhada, criar um segmento de trabalho e passar alguns dados para ele.

    o index.html arquivo contém o roteiro principal dentro de um tag, como você pode ver abaixo:

     const w = new Worker ('worker.js'); var n = 9; w.postMessage (n); 

    o worker.js arquivo carrega o roteiro do trabalhador:

     onmessage = (e) => console.group ('[trabalhador]'); console.log ('Dados recebidos do thread principal:% i', e.data); console.groupEnd ();  

    Usando o código acima, obtemos o seguinte saída no console:

     [trabalhador] Dados recebidos do thread principal: 9 

    Você pode ler o meu post mencionado acima em trabalhadores da web para obter a explicação completa do código dos snippets acima.

    Por enquanto, lembre-se de que os dados são enviado de um lado para outro entre tópicos usando o postar mensagem() método. Os dados são recebido do outro lado pelo mensagem manipulador de eventos, como o valor do evento dados propriedade.

    Agora, se nós mudar os dados Ele aparecerá atualizado no final do recebimento? Vamos ver:

     const w = new Worker ('worker.js'); var n = 9; w.postMessage (n); n = 1; 

    Como esperado, o dados tem não foi atualizado:

     [trabalhador] Dados recebidos do thread principal: 9 

    Por que seria assim? Está apenas um clone enviado para o trabalhador a partir do roteiro principal.

    Trabalhadores da Web com memoria compartilhada

    Agora vamos use o SharedArrayBuffer objeto no mesmo exemplo. Nós podemos criar um novo SharedArrayBuffer exemplo por usando o Novo palavra chave. O construtor usa um parâmetro; uma valor do comprimento em bytes, especificando o tamanho do buffer.

     const w = new Worker ('worker.js'); buff = new SharedArrayBuffer (1); var arr = new Int8Array (buff); / * dados de configuração * / arr [0] = 9; / * enviando o buffer (cópia) para worker * / w.postMessage (buff); 

    Note que um SharedArrayBuffer objeto representa apenas uma área de memória compartilhada. Para ver e alterar os dados binários, precisamos usar uma estrutura de dados apropriada TypedArray ou um Exibição de dados objeto).

    No index.html arquivo acima, um novo SharedArrayBuffer é criado, com apenas um byte de comprimento. Então, um novo Int8Array, que é um tipo de TypedArray objetos, é usado para definir os dados para “9” no espaço de bytes fornecido.

     onmessage = (e) => var arr = novo Int8Array (e.data); console.group ('[worker]'); console.log ('Dados recebidos do encadeamento principal:% i', arr [0]); console.groupEnd ();  

    Int8Array também é usado no trabalhador, para ver os dados no buffer.

    o valor esperado aparece no console do thread de trabalho, que é exatamente o que nós queríamos:

     [trabalhador] Dados recebidos do thread principal: 9 

    Agora vamos atualizar os dados no segmento principal para ver se a mudança é refletida no trabalhador.

     const w = new Worker ('worker.js'), buff = novo SharedArrayBuffer (1); var arr = new Int8Array (buff); / * dados de configuração * / arr [0] = 9; / * enviando o buffer (cópia) para worker * / w.postMessage (buff); / * alterando os dados * / arr [0] = 1;

    E, como você pode ver abaixo, a atualização reflete dentro do trabalhador!

     [trabalhador] Dados recebidos do thread principal: 1 

    Mas o código também precisa trabalhar ao contrário: quando o valor no trabalhador muda no início, também precisa ser atualizado quando é impresso a partir do segmento principal.

    Neste caso, nosso código se parece com isto:

     onmessage = (e) => var arr = novo Int8Array (e.data); console.group ('[worker]'); console.log ('Dados recebidos do encadeamento principal:% i', arr [0]); console.groupEnd (); / * alterando os dados * / arr [0] = 7; / * postagem no segmento principal * / postMessage ("); 

    o os dados são alterados no trabalhador e um mensagem vazia é postada no tópico principal sinalização de que os dados no buffer foram alterados e estão prontos para o thread principal ser gerado.

     const w = new Worker ('worker.js'), buff = novo SharedArrayBuffer (1); var arr = new Int8Array (buff); / * dados de configuração * / arr [0] = 9; / * enviando o buffer (cópia) para worker * / w.postMessage (buff); / * alterando os dados * / arr [0] = 1; / * imprimindo os dados após o trabalhador ter alterado * / w.onmessage = (e) => console.group ('[main]'); console.log ('Dados atualizados recebidos do thread de trabalho:% i', arr [0]); console.groupEnd ();  

    E isso também funciona! Os dados no buffer são os mesmos que os dados dentro do trabalhador.

     [trabalhador] Dados recebidos do thread principal: 1 [main] Dados atualizados recebidos do thread de trabalho: 7 

    O valor que aparece atualizado em ambos os casos; os threads principal e de trabalho estão exibindo e alterando os mesmos dados.

    Palavras finais

    Como mencionei anteriormente, usando memória compartilhada em JavaScript não é sem desvantagens. Cabe aos desenvolvedores garantir que o seqüência de execução acontece como previsto e não há dois segmentos estão correndo para obter os mesmos dados, porque ninguém sabe quem vai levar o troféu.

    Se você está mais interessado em memória compartilhada, dê uma olhada na documentação do Atomics objeto. o Objeto Atomics pode ajudá-lo com algumas das dificuldades, reduzindo a natureza imprevisível da leitura / escrita da memória compartilhada.