SharedArrayBuffer i JavaScript

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 til 200. 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 en Int32Array 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 af name-egenskaben: waiter (ventende rolle) og notifier (notificerende rolle). Til sidst gives den delte buffer til begge workers, og onmessage-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 af Atomics.wait, så længe værdien på indeks 0 er 0. Når notifier-workeren derimod ændrer værdien til 123 med Atomics.store og kalder Atomics.notify, vil waiter-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 skal Cross-Origin-Opener-Policy og Cross-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.

YouTube Video