SharedArrayBuffer i JavaScript
Denne artikel forklarer SharedArrayBuffer
i JavaScript.
Vi vil give en detaljeret forklaring af grundlæggende om SharedArrayBuffer
, hvordan man bruger det, specifikke anvendelsestilfælde og sikkerhedsovervejelser.
YouTube Video
SharedArrayBuffer i JavaScript
SharedArrayBuffer
er et effektivt værktøj i JavaScript til at dele hukommelse mellem flere tråde. Især i kombination med Web Workers muliggør det parallel behandling, hvilket gør det effektivt til beregningstunge opgaver og applikationer, der kræver realtidsfunktionalitet.
Hvad er SharedArrayBuffer?
SharedArrayBuffer
giver en hukommelsesbuffer i JavaScript, der muliggør deling af binære data mellem flere tråde (primært Web Workers). En almindelig ArrayBuffer
kræver kopiering mellem hovedtråden og arbejdstrådene, men SharedArrayBuffer
tillader direkte hukommelsesdeling uden kopiering, hvilket væsentligt forbedrer ydeevnen.
Funktioner
- Delt hukommelse Det tillader flere tråde at arbejde med det samme hukommelsesområde.
- Ydelsesforbedring Da kopiering kan udelades, reduceres overheaden, når store datamængder behandles.
- Trådsynkronisering
Du kan bruge det sammen med
Atomics
til at udføre synkronisering for at undgå konflikter ved adgang til hukommelsen.
Grundlæggende brugs-eksempel
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 eksempel opretter vi et 16-byte hukommelsesområde ved hjælp af SharedArrayBuffer
og behandler det hukommelsesområde som en Int32Array
. Denne hukommelsesbuffer kan deles mellem flere tråde.
Brug med Web Workers
Den reelle værdi af SharedArrayBuffer
vises, når den bruges sammen med Web Workers. Den følgende kode er et eksempel på brug af delt hukommelse mellem hovedtråden og en arbejdstrå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å Arbejdstrådens Side (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 eksempel opretter hovedtråden en delt buffer og sender den til arbejdstråden. Arbejdstråden kan få adgang til denne buffer for at læse og ændre værdier. På denne måde kan data deles mellem tråde uden kopiering.
Tovejsgodkendelse af opdatering
Ved at bruge SharedArrayBuffer
kan både hovedtråden og arbejdstråde læse og skrive til den samme hukommelse, hvilket muliggør tovejsgodkendelse af opdateringer. Nedenfor er et eksempel, hvor hovedtråden sætter en værdi, en arbejdstråd ændrer denne værdi, og derefter tjekker hovedtråden opdateringen.
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å Arbejdstrådens Side (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 eksempel skriver hovedtråden først værdien
100
, og efter arbejdstråden læser den, ændres den til200
. Derefter underretter arbejdstråden hovedtråden, og hovedtråden læser den delte hukommelse igen for at bekræfte opdateringen. På denne måde gør kombinationen af notifikationer det muligt at bekræfte opdateringer tovejs.
Synkronisering med Atomics
Når man bruger delt hukommelse, skal man være opmærksom på data-kapløbsforhold og inkonsistenser. Når flere tråde får adgang til den samme hukommelse samtidigt, kan der opstå konflikter. For at forhindre dette bruger JavaScript Atomics
-objektet til synkronisering.
For eksempel, for sikkert at øge en tæller med flere tråde, kan du bruge Atomics
til at forhindre 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
øger værdien på en specifik indeks atomisk og returnerer den nye værdi. Denne operation er garanteret konfliktfri med andre tråde. Atomics.load
bruges også til sikkert at læse værdier fra delt hukommelse.
Ventning og notifikation ved brug af Atomics.wait
og Atomics.notify
Når du bruger SharedArrayBuffer
, opstår der situationer, hvor en arbejdstråd skal vente, indtil en bestemt betingelse er opfyldt, og når en anden arbejdstråd opfylder denne betingelse, skal den underrette den ventende tråd. I sådanne tilfælde er Atomics.wait
og Atomics.notify
nyttige.
Atomics.wait
blokerer en tråd, indtil værdien på et bestemt indeks i den delte hukommelse ændres, mens Atomics.notify
underretter ventende tråde om, at de kan fortsætte. Dette muliggør sikker ventning og notifikation mellem flere arbejdstråde. Dog kan Atomics.wait
ikke bruges på hoved-tråden og er kun tilgængelig inde i workers.
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 oprettes en
SharedArrayBuffer
som delt hukommelse, og den konverteres til enInt32Array
med kun ét element. Denne ene heltals-plads bruges som et signal til at synkronisere mellem workers. Derefter oprettes to workers, og hver tildeles en rolle ved hjælp afname
-egenskaben:waiter
(ventende rolle) ognotifier
(notificerende rolle). Til sidst gives den delte buffer til begge workers, ogonmessage
-håndteringer sættes op, så beskeder fra hver worker kan modtages.
På Arbejdstrådens Side (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 eksempel forbliver
waiter
-workeren i en ventetilstand ved hjælp afAtomics.wait
, så længe værdien på indeks0
er0
. Nårnotifier
-workeren derimod ændrer værdien til123
medAtomics.store
og kalderAtomics.notify
, vilwaiter
-workeren fortsætte og kunne hente den opdaterede værdi. Med dette kan effektiv og sikker venten og notifikation mellem tråde opnås.
Anvendelsestilfælde for SharedArrayBuffer
SharedArrayBuffer
er særligt nyttig til følgende anvendelser:.
- Real-tids-behandling Det er velegnet til applikationer, der kræver lav latenstid, såsom lyd- og videobehandling eller spilmotorer, hvor data skal deles øjeblikkeligt mellem tråde.
- Parallel behandling
Når store datamængder behandles samtidigt med flere tråde, undgår brugen af
SharedArrayBuffer
hukommelseskopiering og kan forbedre ydelsen. - Maskinlæring Ved at parallelisere opgaver såsom dataforbehandling og inferens bliver effektiv beregning mulig.
Sikkerhedsovervejelser
SharedArrayBuffer
er en kraftfuld funktion, men den indebærer også sikkerhedsrisici. Specielt bekymringer om sidekanalangreb som Spectre
har midlertidigt stoppet dens understøttelse. For at afhjælpe denne sårbarhed har browsere implementeret følgende foranstaltninger:.
- Site-isolering
Websteder, der tillader brug af
SharedArrayBuffer
, kører i en proces, der er fuldstændig isoleret fra andre websteder. - Cross-Origin Resource Policy
For at bruge
SharedArrayBuffer
skalCross-Origin-Opener-Policy
ogCross-Origin-Embedder-Policy
headerne være korrekt sat.
For eksempel, ved at indstille headere som de følgende, bliver brugen af SharedArrayBuffer
mulig:.
1Cross-Origin-Opener-Policy: same-origin
2Cross-Origin-Embedder-Policy: require-corp
Dette forhindrer eksterne ressourcer i at forstyrre det aktuelle indhold og øger sikkerheden.
Sammendrag
SharedArrayBuffer
er et meget kraftfuldt værktøj til deling af hukommelse mellem flere tråde. Det er en essentiel teknologi til forbedring af ydeevne, og dens effekter er særligt tydelige inden for realtime-behandling og parallel computing. Dog indebærer det også sikkerhedsrisici, så korrekt konfiguration og synkronisering er vigtige.
Ved at udnytte SharedArrayBuffer
kan du bygge mere avancerede og højtydende webapplikationer.
Du kan følge med i ovenstående artikel ved hjælp af Visual Studio Code på vores YouTube-kanal. Husk også at tjekke YouTube-kanalen.