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 til200
. 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 etInt32Array
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 avname
-egenskapen:waiter
(ventende rolle) ognotifier
(varsler-rollen). Til slutt sendes den delte bufferen til begge workerne, ogonmessage
-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 å brukeAtomics.wait
så lenge verdien på indeks0
er0
. På den annen side, nårnotifier
-workeren endrer verdien til123
medAtomics.store
og kallerAtomics.notify
, vilwaiter
-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å overskrifteneCross-Origin-Opener-Policy
ogCross-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.