Inleiding tot gedeeld geheugen in JavaScript
Gedeelde herinnering is een geavanceerde functie van JavaScript, die threads (gelijktijdig uitgevoerde delen van een proces) kunnen gebruiken. Het delen van het geheugen betekent niet de moeite hebben om bijgewerkte gegevens door te geven tussen threads en alle threads kunnen dezelfde gegevens in het gedeelde geheugen openen en bijwerken.
Klinkt dat niet heerlijk? Nou bijna. In deze post zullen we zien hoe gedeeld geheugen te gebruiken in JavaScript en hoe je kunt beslissen of dit is wat je echt wilt doen.
Voor- en nadelen van gedeeld geheugen
We gebruiken webmedewerkers naar maak threads in JavaScript. Met de Web Workers API kunnen we werkthreads maken die kunnen worden gebruikt voer code uit op de achtergrond zodat de hoofdthema vrij is om door te gaan met de uitvoering, eventueel het verwerken van UI-gebeurtenissen, zodat er geen bevriezing van de gebruikersinterface is.
Werkstersdraden samen met de hoofdthread en met elkaar uitgevoerd. Een dergelijke gelijktijdige uitvoering van verschillende delen van een taak is tijdbesparend. Je eindigt sneller, maar het heeft ook zijn eigen reeks problemen.
Zorg ervoor dat elke draad krijgt de benodigde middelen en communiceert tijdig met elkaar is een taak op zich, waarbij een incident kan resulteren in een verrassend resultaat. Of als een thread is het veranderen van gegevens en een andere is het aan het lezen tegelijkertijd, wat denk je dat de andere thread zal zien? De bijgewerkte of de oude gegevens?
Webwerkers zijn echter niet zo gemakkelijk te verknoeien. Tijdens hun communicatie via het gebruik van berichten, is de data die ze elkaar sturen wel niet origineel maar een kopie, wat betekent dat ze dat niet doen delen dezelfde gegevens. Ze Kopieën van gegevens aan elkaar doorgeven wanneer nodig.
Maar delen is zorgzaam, en meerdere threads moeten mogelijk ook tegelijkertijd naar dezelfde gegevens kijken en deze wijzigen. Zo, het verbieden van delen is een grote no-no. Dit is waar de SharedArrayBuffer
object komt in beeld. Het zal ons laten deel binaire gegevens tussen meerdere threads.
De SharedArrayBuffer
voorwerp
In plaats van de gegevenskopieën tussen threads door te geven, wij geef kopieën van de SharedArrayBuffer
voorwerp. EEN SharedArrayBuffer
voorwerp wijst naar het geheugen waarin de gegevens zijn opgeslagen.
Dus zelfs wanneer de kopieën van SharedArrayBuffer
worden doorgegeven tussen threads, zij alles wijst nog steeds naar hetzelfde geheugen waar de originele gegevens worden opgeslagen. De draden kunnen dus bekijk en update de gegevens in datzelfde geheugen.
Webarbeiders zonder gedeelde herinnering
Om te zien hoe een webwerker werkt zonder gedeeld geheugen te gebruiken, wij maak een werkthread en geef wat gegevens door.
De index.html
bestand bevat de hoofdscript in een tag, zoals je hieronder kunt zien:
const w = new Worker ('worker.js'); var n = 9; w.postMessage (n);
De worker.js
bestand draagt de werksterscript:
onmessage = (e) => console.group ('[worker]'); console.log ('Gegevens ontvangen van hoofdthema:% i', e.data); console.groupEnd ();
Met behulp van bovenstaande code krijgen we het volgende uitvoer in de console:
[worker] Gegevens ontvangen van de hoofdthema: 9
Je kunt mijn voornoemde bericht op webwerkers lezen voor de volledige codeaanduiding van de bovenstaande fragmenten.
Houd er nu rekening mee dat gegevens dat zijn heen en weer gestuurd tussen threads de ... gebruiken postMessage ()
methode. De gegevens zijn aan de andere kant ontvangen door de bericht
gebeurtenishandler, als de waarde van de gebeurtenissen gegevens
eigendom.
Nu, als wij verander de gegevens zal het verschijnen aan de ontvangende kant? Laten we eens kijken:
const w = new Worker ('worker.js'); var n = 9; w.postMessage (n); n = 1;
Zoals verwacht, de data heeft niet zijn bijgewerkt:
[worker] Gegevens ontvangen van de hoofdthema: 9
Waarom zou het eigenlijk zijn? Haar gewoon een kloon die vanuit het hoofdscript naar de medewerker is verzonden.
Webarbeiders met gedeelde herinnering
Dat zullen we nu doen gebruik de SharedArrayBuffer
voorwerp in hetzelfde voorbeeld. We kunnen een nieuwe maken SharedArrayBuffer
bijvoorbeeld door de ... gebruiken nieuwe
trefwoord. De constructor neemt één parameter; een lengtewaarde in bytes, specificatie van de grootte van de buffer.
const w = new Worker ('worker.js'); buff = nieuwe SharedArrayBuffer (1); var arr = new Int8Array (buff); / * gegevens instellen * / arr [0] = 9; / * verzenden van de buffer (kopie) naar worker * / w.postMessage (buff);
Merk op dat a SharedArrayBuffer
voorwerp vertegenwoordigt alleen een gedeeld geheugengebied. Naar zie en verander de binaire gegevens, we moeten een geschikte gegevensstructuur gebruiken (a TypedArray
of a Gegevensweergave
voorwerp).
In de index.html
bestand hierboven, een nieuw SharedArrayBuffer
is gemaakt, met slechts één-bytelengte. Toen, een nieuwe Int8Array
, dat is een type TypedArray
objecten, is gewend aan stel de gegevens in “9” in de byte-ruimte.
onmessage = (e) => var arr = new Int8Array (e.data); console.group ( '[werknemer]'); console.log ('Gegevens ontvangen van hoofdthema:% i', arr [0]); console.groupEnd ();
Int8Array
wordt ook gebruikt in de werker, om bekijk de gegevens in de buffer.
De verwachte waarde verschijnt in de console van de worker-thread, en dat is precies wat we wilden:
[worker] Gegevens ontvangen van de hoofdthema: 9
Laten we nu werk de gegevens in de hoofdthread bij om te zien of de verandering wordt weerspiegeld in de werknemer.
const w = new Worker ('worker.js'), buff = new SharedArrayBuffer (1); var arr = new Int8Array (buff); / * gegevens instellen * / arr [0] = 9; / * verzenden van de buffer (kopie) naar worker * / w.postMessage (buff); / * wijzigen van de gegevens * / arr [0] = 1;
En, zoals u hieronder kunt zien, de update reflecteert binnen de werknemer!
[worker] Gegevens ontvangen van de hoofdthema: 1
Maar de code ook moet andersom werken: wanneer de waarde in de werknemer in eerste instantie verandert, is het moet ook worden bijgewerkt wanneer het wordt afgedrukt vanaf de rode draad.
In dit geval ziet onze code er als volgt uit:
onmessage = (e) => var arr = new Int8Array (e.data); console.group ( '[werknemer]'); console.log ('Gegevens ontvangen van hoofdthema:% i', arr [0]); console.groupEnd (); / * wijzigen van de gegevens * / arr [0] = 7; / * posten naar de hoofdthema * / postMessage (");
De gegevens worden in de werknemer gewijzigd en een leeg bericht is geplaatst in de rode draad signalering dat de data in de buffer is veranderd en klaar is om de hoofdthread uit te voeren.
const w = new Worker ('worker.js'), buff = new SharedArrayBuffer (1); var arr = new Int8Array (buff); / * gegevens instellen * / arr [0] = 9; / * verzenden van de buffer (kopie) naar worker * / w.postMessage (buff); / * wijzigen van de gegevens * / arr [0] = 1; / * afdrukken van de gegevens nadat de medewerker deze heeft gewijzigd * / w.onmessage = (e) => console.group ('[main]'); console.log ('bijgewerkte gegevens ontvangen van werkthread:% i', arr [0]); console.groupEnd ();
En, dit werkt ook! De gegevens in de buffer zijn hetzelfde als de gegevens in de werknemer.
[worker] Gegevens ontvangen van de hoofdthema: 1 [hoofd] Bijgewerkte gegevens ontvangen van worker thread: 7
De waarde verschijnt in beide gevallen bijgewerkt; zowel de hoofd- als werkthreads bekijken en wijzigen dezelfde gegevens.
Laatste woorden
Zoals ik eerder al heb gezegd, gebruikmakend van gedeeld geheugen in JavaScript is niet zonder nadelen. Het is aan ontwikkelaars om ervoor te zorgen dat de volgorde van uitvoering gebeurt zoals voorspeld en geen twee threads racen om dezelfde gegevens te krijgen omdat niemand weet wie de trofee zal nemen.
Als u meer geïnteresseerd bent in gedeeld geheugen, bekijk dan de documentatie van de Kernfysica
voorwerp. De Atomics-object kan u helpen bij enkele van de ontberingen, door het onvoorspelbare karakter van lezen / schrijven uit het gedeelde geheugen te verminderen.