Pagrindinis » Kodavimas » Įvadas į bendrinamą atmintį „JavaScript“

    Įvadas į bendrinamą atmintį „JavaScript“

    Bendroji atmintis yra pažangi „JavaScript“ funkcija, kad siūlai (tuo pačiu metu vykdomos proceso dalys) gali sverti. Dalijimasis atminties priemonėmis nepavyko perduoti atnaujintų duomenų tarp sričių ir visi siūlai gali pasiekti ir atnaujinti tuos pačius duomenis bendroje atmintyje.

    Ar tai negerai? Na, beveik. Šiame pranešime matysime kaip naudoti bendrąją atmintį „JavaScript“ ir kaip nuspręsti, ar tai yra tai, ką jūs tikrai norite padaryti.

    Bendrosios atminties privalumai ir trūkumai

    Mes naudojame žiniatinklio darbuotojai į kurti temas „JavaScript“. „Web Workers“ API leidžia mums sukurti darbuotojo temas, kurios gali būti naudojamos vykdykite kodą fone taip, kad pagrindinis sriegis galėtų laisvai tęsti jo vykdymą, galbūt apdorojant UI įvykius, užtikrinant, kad nebūtų UI užšaldymo.

    Darbuotojų siūlai paleisti kartu su pagrindiniu sriegiu ir vienas kitą. Toks vienalaikis skirtingų užduočių dalių vykdymas yra taupymas. Jūs baigsite greičiau, bet taip pat turite savo problemų rinkinį.

    Įsitikinkite, kad kiekvienas gija gauna reikiamus išteklius ir laiku bendrauja tarpusavyje yra užduotis savaime, kai nesėkmė gali sukelti nuostabų rezultatą. Arba jeigu vienas siūlas keičia duomenis ir kitas skaito Tuo pačiu metu, Ką, jūsų nuomone, matys kitas temas? Atnaujinti arba seni duomenys?

    Tačiau žiniatinklio darbuotojai nėra taip lengva prisukti. Ryšiai, naudojant pranešimus, yra jų siunčiami duomenys ne originalas, o kopija, reiškia, kad jie neturi Dalintis tuos pačius duomenis. Jie perduoti duomenų kopijas viena kitai Kai reikia.

    Tačiau dalijimasis yra rūpestingas, o kelioms temoms taip pat gali tekti pažiūrėti tuos pačius duomenis tuo pačiu metu ir juos keisti. Taigi, draudimas dalytis yra didelis ne-ne. Štai kur SharedArrayBuffer objektas ateina į paveikslėlį. Jis mums leis dalintis dvejetainiais duomenimis tarp kelių sričių.

    The SharedArrayBuffer objektą

    Užuot perdavę duomenų kopijas tarp siūlų, mes perduoti kopijas SharedArrayBuffer objektą. A SharedArrayBuffer objektą nukreipia į atmintį, kurioje saugomi duomenys.

    Taigi, net ir tada, kai kopijos SharedArrayBuffer yra perduodami tarp sričių, jie visi bus nukreipti į tą pačią atmintį išsaugoti originalūs duomenys. Taigi siūlai gali peržiūrėti ir atnaujinti tos pačios atminties duomenis.

    Žiniatinklio darbuotojai be bendroji atmintis

    Norėdami pamatyti, kaip žiniatinklio darbuotojas dirba be bendrosios atminties, mes sukurti darbuotojo siūlą ir perduoti tam tikrus duomenis.

    The index.html failas turi pagrindinis scenarijus viduje žyma, kaip matote toliau:

     const w = naujas darbuotojas ('worker.js'); var n = 9; w.postMessage (n); 

    The worker.js faile yra darbuotojo scenarijus:

     onmessage = (e) => console.group („[darbuotojas]“); console.log („Duomenys gauti iš pagrindinės temos:% i“, e.data); console.groupEnd ();  

    Naudojant aukščiau pateiktą kodą, mes gauname šiuos duomenis išvesties konsolėje:

     [darbuotojas] Duomenys gauti iš pagrindinės temos: 9 

    Pirmiau minėtą žinią žiniatinklio darbuotojams galite perskaityti išsamiu pirmiau minėtų fragmentų kodo paaiškinimu.

    Dabar atminkite, kad duomenys yra siunčiami į priekį ir atgal naudojant postMessage () metodas. Duomenys yra iš kitos pusės gavo pranešimą įvykių tvarkytojas, kaip įvykio vertė duomenis nuosavybė.

    Dabar, jei mes keisti duomenis ar jis bus atnaujintas priimančiojoje vietoje? Pažiūrėkime:

     const w = naujas darbuotojas ('worker.js'); var n = 9; w.postMessage (n); n = 1; 

    Kaip tikėtasi, duomenys ne atnaujinta:

     [darbuotojas] Duomenys gauti iš pagrindinės temos: 9 

    Kodėl taip būtų? Tai tik klonas, išsiųstas darbuotojui iš pagrindinio scenarijaus.

    Žiniatinklio darbuotojai su bendroji atmintis

    Dabar mes naudoti SharedArrayBuffer objektą tame pačiame pavyzdyje. Galime sukurti naują SharedArrayBuffer pavyzdžiui, naudojant naujas raktinis žodis. Konstruktorius turi vieną parametrą; a ilgio vertė baitais, nurodant buferio dydį.

     const w = naujas darbuotojas ('worker.js'); buff = new SharedArrayBuffer (1); var arr = naujas Int8Array (buff); / * nustatymo duomenys * / arr [0] = 9; / * siunčia buferį (kopiją) darbuotojui * / w.postMessage (buff); 

    Atkreipkite dėmesį, kad a SharedArrayBuffer objektą reiškia tik bendrai naudojamą atminties sritį. Į matyti ir keisti dvejetainius duomenis, turime naudoti tinkamą duomenų struktūrą (a TypedArray arba a „DataView“ objektas).

    Viduje konors index.html failą, naują SharedArrayBuffer sukurtas tik vieno baito ilgio. Tada naujas Int8Array, kuris yra vieno tipo TypedArray objektų nustatyti duomenis “9” numatytoje baito erdvėje.

     onmessage = (e) => var arr = naujas Int8Array (e.data); console.group („[darbuotojas]“); console.log ('Duomenys, gauti iš pagrindinio gijos:% i', arr [0]); console.groupEnd ();  

    Int8Array taip pat naudojamas darbuotojui peržiūrėti duomenis buferyje.

    The laukiama vertė rodoma konsolėje iš darbuotojo gijos, būtent tai, ko mes norėjome:

     [darbuotojas] Duomenys gauti iš pagrindinės temos: 9 

    Dabar, tegul atnaujinti pagrindinio gijos duomenis pamatyti, ar darbuotojas pasikeičia.

     const w = naujas darbuotojas ('worker.js'), buff = naujas SharedArrayBuffer (1); var arr = naujas Int8Array (buff); / * nustatymo duomenys * / arr [0] = 9; / * siunčia buferį (kopiją) darbuotojui * / w.postMessage (buff); / * duomenų keitimas * / arr [0] = 1;

    Ir, kaip matote toliau, atnaujinimas atspindi darbuotojo viduje!

     [darbuotojas] Duomenys gauti iš pagrindinės temos: 1 

    Bet, kodą taip pat reikia dirbti atvirkščiai: kai darbuotojo vertė pasikeičia iš pradžių, ji taip pat reikia atnaujinti kai jis spausdinamas iš pagrindinio gijos.

    Tokiu atveju mūsų kodas atrodo taip:

     onmessage = (e) => var arr = naujas Int8Array (e.data); console.group („[darbuotojas]“); console.log ('Duomenys, gauti iš pagrindinio gijos:% i', arr [0]); console.groupEnd (); / * duomenų keitimas * / arr [0] = 7; / * skelbimas pagrindiniam sriegiui * / postMessage ("); 

    The duomenys keičiami darbuotojoje ir a tuščias pranešimas siunčiamas į pagrindinį siūlą signalas, kad buferio duomenys buvo pakeisti ir yra pasirengę išleisti pagrindinį sriegį.

     const w = naujas darbuotojas ('worker.js'), buff = naujas SharedArrayBuffer (1); var arr = naujas Int8Array (buff); / * nustatymo duomenys * / arr [0] = 9; / * siunčia buferį (kopiją) darbuotojui * / w.postMessage (buff); / * duomenų keitimas * / arr [0] = 1; / * spausdinti duomenis po to, kai darbuotojas jį pakeitė * / w.onmessage = (e) => console.group ('[main]'); console.log („Atnaujinti duomenys, gauti iš darbuotojo siūlų:% i“, arr [0]); console.groupEnd ();  

    Ir tai taip pat veikia! Duomenys buferyje yra tokie pat, kaip ir darbuotojo duomenys.

     [darbuotojas] Duomenys, gauti iš pagrindinio gijos: 1 [pagrindinis] Atnaujinti duomenys, gauti iš darbuotojo gijos: 7 

    Vertė abiejose bylose yra atnaujinama; tiek pagrindiniai, tiek darbuotojo siūlai žiūri ir keičia tuos pačius duomenis.

    Galutiniai žodžiai

    Kaip minėjau anksčiau, naudodamasis „JavaScript“ bendrai naudojamą atmintį nėra be jokio neigiamo poveikio. Tai iki kūrėjams užtikrinti, kad vykdymo seka vyksta taip, kaip buvo numatyta ir jokios dvi temos nėra lenktynės, kad gautų tuos pačius duomenis, nes niekas nežino, kas trofėjaus.

    Jei jus domina bendresnė atmintis, pažiūrėkite į dokumentaciją Atomika objektą. The Atomikos objektas gali padėti jums su kai kuriais sunkumais, mažinant nenuspėjamą skaitymo / rašymo iš bendrosios atminties pobūdį.