Introduktion til delt hukommelse i JavaScript
Delt hukommelse er en avanceret funktion af JavaScript, at tråde (samtidigt udførte dele af en proces) kan udnytte. Deling af hukommelsesmidlerne ikke har problemer med at sende opdaterede data mellem tråde og alle tråde kan få adgang til og opdatere de samme data i den delte hukommelse.
Lyder det ikke dejligt? Nå, næsten. I dette indlæg vil vi se Sådan bruger du delt hukommelse i JavaScript og hvordan man beslutter, om dette er det, du virkelig vil gøre.
Fordele og ulemper ved delt hukommelse
Vi bruger webarbejdere til Opret tråde i JavaScript. Webarbejds-API'en giver os mulighed for at oprette arbejdstråde, der kan bruges til udfør kode i baggrunden så hovedtråden er fri til at fortsætte dens udførelse, muligvis forarbejdning af brugergrænseflader, hvilket sikrer, at der ikke fryses.
Arbejdstråde køre samtidigt med hovedtråden og hinanden. Sådan samtidig udførelse af forskellige dele af en opgave er tidsbesparende. Du klarer hurtigere, men det har også sit eget sæt problemer.
Sørg for at hver tråd får de nødvendige ressourcer og kommunikerer med hinanden rettidigt er en opgave i sig selv, hvor et uheld kan resultere i et overraskende resultat. Eller, hvis en tråd ændrer data, og en anden læser den på samme tid, hvad tror du den anden tråd vil se? Den opdaterede eller de gamle data?
Men webarbejdere er ikke så let at skrue op. Under deres kommunikation via brug af meddelelser er de data, de sender hinanden, ikke originalt, men en kopi, hvilket betyder at de ikke gør det del de samme data. De send kopier af data til hinanden når det er nødvendigt.
Men deling er omhyggelig, og flere tråde kan muligvis også se på de samme data på samme tid og ændre dem. Så, forbud mod deling er et stort nej-nej. Det er her SharedArrayBuffer
objekt kommer ind i billedet. Det vil lade os dele binære data mellem flere tråde.
Det SharedArrayBuffer
objekt
I stedet for at sende datakopierne mellem trådene, vi send kopier af SharedArrayBuffer
objekt. EN SharedArrayBuffer
objekt peger på hukommelsen, hvor dataene gemmes.
Så selv når kopierne af SharedArrayBuffer
er passeret mellem tråde, de alle vil stadig pege på den samme hukommelse hvor de oprindelige data er gemt. Trådene kan således se og opdater dataene i samme hukommelse.
Webarbejdere uden delt hukommelse
For at se, hvordan en webarbejder virker uden at bruge delt hukommelse, vi opret en arbejdstråd tråd og send nogle data til den.
Det index.html
filen indeholder hovedskript inde i a tag, som du kan se det nedenfor:
const w = nyarbejder ('worker.js'); var n = 9; w.postMessage (n);
Det worker.js
filen bærer arbejdstager script:
onmessage = (e) => console.group ('[worker]'); console.log ('Data modtaget fra hovedtråden:% i', e.data); console.groupEnd ();
Ved hjælp af koden ovenfor får vi følgende output i konsollen:
[medarbejder] Data modtaget fra hovedtråden: 9
Du kan læse mit førnævnte indlæg på webarbejdere for hele kodeforklaringen af ovenstående uddrag.
For nu, husk at data er sendt frem og tilbage mellem trådene bruger postMessage ()
metode. Dataene er modtaget på den anden side af besked
hændelseshandler, som værdien af arrangementet er data
ejendom.
Nu, hvis vi ændre dataene vil det blive opdateret i modtagelsesenden? Lad os se:
const w = nyarbejder ('worker.js'); var n = 9; w.postMessage (n); n = 1;
Som forventet data har ikke blevet opdateret:
[medarbejder] Data modtaget fra hovedtråden: 9
Hvorfor ville det være alligevel? Det er bare en klon sendt til arbejderen fra hovedskriptet.
Webarbejdere med delt hukommelse
Nu vil vi brug SharedArrayBuffer
objekt i samme eksempel. Vi kan oprette en ny SharedArrayBuffer
forekomst af bruger ny
søgeord. Konstruktøren tager en parameter; -en længdeværdi i byte, angivelse af bufferens størrelse.
const w = nyarbejder ('worker.js'); buff = ny SharedArrayBuffer (1); var arr = ny Int8Array (buff); / * indstillingsdata * / arr [0] = 9; / * sende buffer (kopi) til medarbejder * / w.postMessage (buff);
Bemærk at a SharedArrayBuffer
objekt repræsenterer kun et delt hukommelsesområde. Til se og ændre binære data, vi skal bruge en passende datastruktur (a TypedArray
eller a DataView
objekt).
I index.html
fil ovenfor, en ny SharedArrayBuffer
er oprettet med kun en byte længde. Så en ny Int8Array
, som er en type af TypedArray
objekter, er vant til indstil dataene til “9” i det medfølgende byte rum.
onmessage = (e) => var ar = ny Int8Array (e.data); console.group ( '[arbejder]'); console.log ('Data modtaget fra hovedtråden:% i', arr [0]); console.groupEnd ();
Int8Array
bruges også i arbejderen til se data i bufferen.
Det forventet værdi vises i konsollen fra arbejdetråden, hvilket er præcis det, vi ønskede:
[medarbejder] Data modtaget fra hovedtråden: 9
Lad os nu opdater dataene i hovedtråden for at se om ændringen afspejles i arbejderen.
const w = nyarbejder ('worker.js'), buff = ny SharedArrayBuffer (1); var arr = ny Int8Array (buff); / * indstillingsdata * / arr [0] = 9; / * sende buffer (kopi) til medarbejder * / w.postMessage (buff); / * Ændring af dataene * / arr [0] = 1;
Og som du kan se nedenfor, opdateringen reflekterer inde i arbejderen!
[medarbejder] Data modtaget fra hovedtråd: 1
Men koden også skal arbejde omvendt: Når værdien i arbejderen ændres i første omgang, er den skal også opdateres når den er trykt fra hovedtråden.
I dette tilfælde ser vores kode sådan ud:
onmessage = (e) => var ar = ny Int8Array (e.data); console.group ( '[arbejder]'); console.log ('Data modtaget fra hovedtråden:% i', arr [0]); console.groupEnd (); / * ændre data * / arr [0] = 7; / * udstationering til hovedtråden * / postMessage (");
Det data ændres i arbejderen og en tom besked er sendt til hovedtråden signalerer, at dataene i bufferen er blevet ændret og er klar til at hovedgruppen udleveres.
const w = nyarbejder ('worker.js'), buff = ny SharedArrayBuffer (1); var arr = ny Int8Array (buff); / * indstillingsdata * / arr [0] = 9; / * sende buffer (kopi) til medarbejder * / w.postMessage (buff); / * Ændring af dataene * / arr [0] = 1; / * Udskrivning af data efter at medarbejderen har ændret det * / w.onmessage = (e) => console.group ('[main]'); console.log ('Opdaterede data modtaget fra arbejdstråd:% i', arr [0]); console.groupEnd ();
Og det virker også! Dataene i bufferen er de samme som dataene inden for arbejderen.
[medarbejder] Data modtaget fra hovedtråden: 1 [main] Opdaterede data modtaget fra arbejdstråd: 7
Værdien vises opdateret i begge sager; både hoved- og arbejdstrådene ser og ændrer de samme data.
Afsluttende ord
Som jeg har nævnt tidligere, bruger du delt hukommelse i JavaScript er ikke uden ulemper. Det er op til udviklere at sikre, at sekvens af udførelse sker som forudsagt og ingen to tråde kører for at få de samme data, fordi ingen ved hvem der vil tage trofæet.
Hvis du er interesseret i delt hukommelse mere, skal du kigge på dokumentationen af Atomics
objekt. Det Atomics objekt kan hjælpe dig med nogle af de vanskeligheder, ved at reducere den uforudsigelige karakter af læsning / skrivning fra den delte hukommelse.