SharedArrayBuffer i JavaScript

SharedArrayBuffer i JavaScript

Denne artikkelen forklarer SharedArrayBuffer i JavaScript.

Vi vil gi en detaljert forklaring av grunnleggende konsepter for SharedArrayBuffer, hvordan det brukes, spesifikke bruksområder, og sikkerhetsaspekter.

YouTube Video

SharedArrayBuffer i JavaScript

SharedArrayBuffer er et kraftig verktøy i JavaScript for å dele minne mellom flere tråder. Spesielt i kombinasjon med Web Workers, muliggjør det parallell behandling, noe som gjør det effektivt for beregningstunge oppgaver og applikasjoner som krever sanntidsfunksjonalitet.

Hva er SharedArrayBuffer?

SharedArrayBuffer gir en minnebuffer i JavaScript som lar deling av binærdata mellom flere tråder (hovedsakelig Web Workers). En vanlig ArrayBuffer krever kopiering mellom hovedtråden og arbeidstrådene, men SharedArrayBuffer tillater direkte deling av minnet uten kopiering, og forbedrer dermed ytelsen betydelig.

Funksjoner

  • Delt Minne Det gjør det mulig for flere tråder å jobbe med det samme minneområdet.
  • Ytelsesforbedring Siden kopiering kan utelates, reduseres overheaden ved behandling av store datamengder.
  • Trådsynkronisering Du kan bruke det sammen med Atomics for å gjennomføre synkronisering og unngå konflikter ved minnetilgang.

Grunnleggende brukseksempel

 1// Create a 16-byte shared memory
 2const sharedBuffer = new SharedArrayBuffer(16);
 3
 4// Treat it as an Int32Array
 5const sharedArray = new Int32Array(sharedBuffer);
 6
 7// Set a value
 8sharedArray[0] = 42;
 9
10console.log(sharedArray[0]);  // 42

I dette eksempelet oppretter vi et 16-bytes minneområde ved hjelp av SharedArrayBuffer og behandler dette minneområdet som en Int32Array. Denne minnebufferen kan deles mellom flere tråder.

Bruk med Web Workers

Den virkelige verdien av SharedArrayBuffer vises når den brukes i kombinasjon med Web Workers. Følgende kode er et eksempel på bruk av delt minne mellom hovedtråden og en arbeidstråd.

På hovedtråden

 1// Create a shared buffer
 2const sharedBuffer = new SharedArrayBuffer(16);
 3const sharedArray = new Int32Array(sharedBuffer);
 4
 5// Create a worker
 6const worker = new Worker('worker.js');
 7
 8// Pass the shared buffer to the worker
 9worker.postMessage(sharedBuffer);
10
11// Modify the memory
12// Output : Main thread: 100
13sharedArray[0] = 100;
14console.log("Main thread: ", sharedArray[0]);

På arbeidstråden (worker.js)

 1// worker.js
 2self.onmessage = function(event) {
 3    // Use the received shared buffer
 4    const sharedArray = new Int32Array(event.data);
 5
 6    // Read the contents of the memory
 7    // Output : Worker thread: 100
 8    console.log("Worker thread: ", sharedArray[0]);
 9
10    // Change the value
11    sharedArray[0] = 200;
12};
  • I dette eksempelet oppretter hovedtråden en delt buffer og sender den til arbeidstråden. Arbeidstråden kan få tilgang til denne bufferen for å lese og endre verdier. På denne måten kan data deles mellom tråder uten kopiering.

Toveis Oppdateringsbekreftelse

Ved å bruke SharedArrayBuffer kan både hovedtråden og arbeidertrådene lese og skrive til det samme minnet, noe som muliggjør toveis oppdateringsbekreftelse. Nedenfor er et eksempel der hovedtråden setter en verdi, en arbeider endrer denne verdien, og hovedtråden deretter sjekker oppdateringen.

På hovedtråden

 1// Create a shared buffer
 2const sharedBuffer = new SharedArrayBuffer(16);
 3const sharedArray = new Int32Array(sharedBuffer);
 4
 5// Create a worker
 6const worker = new Worker('worker.js');
 7
 8// Pass the shared buffer to the worker
 9worker.postMessage(sharedBuffer);
10
11// Set initial value
12// Output : Main thread initial: 100
13sharedArray[0] = 100;
14console.log("Main thread initial:", sharedArray[0]);
15
16// Listen for worker confirmation
17worker.onmessage = () => {
18    // Output : Main thread after worker update: 200
19    console.log("Main thread after worker update:", sharedArray[0]);
20};

På arbeidstråden (worker.js)

 1// worker.js
 2self.onmessage = function(event) {
 3    const sharedArray = new Int32Array(event.data);
 4
 5    // Read initial value
 6    // Output : Worker thread received: 100
 7    console.log("Worker thread received:", sharedArray[0]);
 8
 9    // Update the value
10    sharedArray[0] = 200;
11
12    // Notify main thread
13    self.postMessage("Value updated");
14};
  • I dette eksempelet skriver hovedtråden verdien 100 først, og etter at arbeideren har lest den, endrer den verdien til 200. Deretter gir arbeideren beskjed til hovedtråden, og hovedtråden leser det delte minnet på nytt for å bekrefte oppdateringen. På denne måten gjør kombinasjon av varsler det mulig med toveis oppdateringsbekreftelse.

Synkronisering med Atomics

Ved bruk av delt minne må man passe på datakappløp og inkonsistenser. Når flere tråder får tilgang til det samme minnet samtidig, kan det oppstå konflikter. For å forhindre dette bruker JavaScript objektet Atomics for synkronisering.

For eksempel, for å trygt øke en teller med flere tråder, kan du bruke Atomics for å unngå konflikter.

1const sharedBuffer = new SharedArrayBuffer(16);
2const sharedArray = new Int32Array(sharedBuffer);
3
4// Increment the counter
5Atomics.add(sharedArray, 0, 1);
6
7console.log(Atomics.load(sharedArray, 0));  // 1

Atomics.add øker verdien på en spesifikk indeks atomisk og returnerer den nye verdien. Denne operasjonen er garantert konfliktfri med andre tråder. Atomics.load brukes også for å trygt lese verdier fra delt minne.

Venter og Varsler Ved Bruk Av Atomics.wait og Atomics.notify

Når du bruker SharedArrayBuffer, kan det oppstå situasjoner der en arbeider må vente til en viss betingelse er oppfylt, og når en annen arbeider oppfyller denne betingelsen, må den varsle den ventende arbeideren. I slike tilfeller er Atomics.wait og Atomics.notify nyttige.

Atomics.wait blokkerer en tråd til verdien på en bestemt indeks i delt minne endres, mens Atomics.notify varsler ventende tråder om at de kan fortsette. Dette muliggjør sikker venting og varsling mellom flere arbeidere. Imidlertid kan ikke Atomics.wait brukes på hovedtråden og er kun tilgjengelig inne i workere.

 1// Create a shared buffer (1 Int32 slot is enough for signaling)
 2const sharedBuffer = new SharedArrayBuffer(4);
 3const sharedArray = new Int32Array(sharedBuffer);
 4
 5// Create workers with names
 6const waiter = new Worker('worker.js', { name: 'waiter' });
 7const notifier = new Worker('worker.js', { name: 'notifier' });
 8
 9// Pass the shared buffer to both
10waiter.postMessage(sharedBuffer);
11notifier.postMessage(sharedBuffer);
12
13// Listen for messages
14waiter.onmessage = (event) => {
15    console.log(`[Main] Message from waiter:`, event.data);
16};
17notifier.onmessage = (event) => {
18    console.log(`[Main] Message from notifier:`, event.data);
19};
  • På hovedtråden opprettes en SharedArrayBuffer som delt minne og konverteres til et Int32Array med kun ett element. Dette ene heltallsporet brukes som et signal for å synkronisere mellom workere. Deretter opprettes to workere, og hver får tildelt en rolle ved hjelp av name-egenskapen: waiter (ventende rolle) og notifier (varsler-rollen). Til slutt sendes den delte bufferen til begge workerne, og onmessage-håndterere settes opp slik at meldinger sendt fra hver worker kan mottas.

På arbeidstråden (worker.js)

 1// worker.js
 2onmessage = (event) => {
 3    const sharedArray = new Int32Array(event.data);
 4
 5    if (self.name === 'waiter') {
 6        postMessage('Waiter is waiting...');
 7        // Wait until notifier signals index 0
 8        Atomics.wait(sharedArray, 0, 0);
 9        postMessage('Waiter was notified!');
10    }
11
12    if (self.name === 'notifier') {
13        postMessage('Notifier is preparing...');
14        setTimeout(() => {
15            // Notify waiter after 2 seconds
16            Atomics.store(sharedArray, 0, 1);
17            Atomics.notify(sharedArray, 0, 1);
18            postMessage('Notifier has sent the signal!');
19        }, 2000);
20    }
21};
22// Output
23// [Main] Message from waiter: Waiter is waiting...
24// [Main] Message from notifier: Notifier is preparing...
25// [Main] Message from notifier: Notifier has sent the signal!
26// [Main] Message from waiter: Waiter was notified!
  • I dette eksempelet forblir waiter-workeren i en ventende tilstand ved å bruke Atomics.wait så lenge verdien på indeks 0 er 0. På den annen side, når notifier-workeren endrer verdien til 123 med Atomics.store og kaller Atomics.notify, vil waiter-workeren fortsette og kunne hente den oppdaterte verdien. Med dette kan effektiv og sikker venting og varsling mellom tråder oppnås.

Bruksområder for SharedArrayBuffer

SharedArrayBuffer er spesielt nyttig for følgende brukstilfeller:.

  • Sanntidsbehandling Det passer for applikasjoner som krever lav ventetid, som lyd- og videobehandling eller spillmotorer, der data må deles umiddelbart mellom tråder.
  • Parallellberegning Når store datamengder behandles samtidig med flere tråder, unngår du minnekopiering ved å bruke SharedArrayBuffer, noe som kan forbedre ytelsen.
  • Maskinlæring Ved å parallellisere oppgaver som dataprosessering og inferens blir effektiv beregning mulig.

Sikkerhetsaspekter

SharedArrayBuffer er en kraftig funksjon, men den medfører også sikkerhetsrisikoer. Spesielt bekymringer om sidekanalangrep som Spectre har midlertidig stoppet støtten for det. For å redusere denne sårbarheten har nettlesere implementert følgende tiltak:.

  • Nettstedsisolasjon Nettsteder som tillater bruk av SharedArrayBuffer vil kjøre i en prosess som er fullstendig isolert fra andre nettsteder.
  • Cross-Origin Ressurspolicy For å bruke SharedArrayBuffer må overskriftene Cross-Origin-Opener-Policy og Cross-Origin-Embedder-Policy være riktig konfigurert.

For eksempel, ved å sette headere som følgende, blir bruken av SharedArrayBuffer mulig:.

1Cross-Origin-Opener-Policy: same-origin
2Cross-Origin-Embedder-Policy: require-corp

Dette forhindrer eksterne ressurser fra å forstyrre det nåværende innholdet og øker sikkerheten.

Sammendrag

SharedArrayBuffer er et svært kraftig verktøy for å dele minne mellom flere tråder. Det er en essensiell teknologi for å forbedre ytelsen, og effekten er spesielt tydelig innen sanntidsbehandling og parallellberegning. Det innebærer imidlertid også sikkerhetsrisikoer, så korrekt konfigurasjon og synkronisering er viktig.

Ved å bruke SharedArrayBuffer kan du lage mer avanserte og høytytende nettapplikasjoner.

Du kan følge med på artikkelen ovenfor ved å bruke Visual Studio Code på vår YouTube-kanal. Vennligst sjekk ut YouTube-kanalen.

YouTube Video