Pagina principala » Codificare » Introducere în memoria partajată în JavaScript

    Introducere în memoria partajată în JavaScript

    Memorie partajată este o caracteristică avansată a JavaScript, că firele (părți executate simultan ale unui proces) pot influența. Împărtășirea mijloacelor de memorie fără a avea probleme de a transmite date actualizate între fire iar toate firele pot accesa și actualiza aceleași date în memoria partajată.

    Nu sună minunat? Ei bine aproape. În acest post, vom vedea cum se utilizează memoria partajată în JavaScript și cum să decideți dacă aceasta este ceea ce într-adevăr doriți să faceți.

    Avantajele și dezavantajele memoriei partajate

    Folosim web workers la creați fire în JavaScript. Aplicația Web Workers API ne permite să creăm fire de lucru care pot fi folosite executați codul în fundal astfel încât thread-ul principal să poată continua execuția, eventual procesarea evenimentelor UI, asigurând că nu se îngheață UI.

    Fire de lucru executați concomitent cu firul principal și reciproc. O astfel de execuție simultană a diferitelor părți ale unei sarcini este de economisire a timpului. Finalizați mai repede, dar are și propriul set de probleme.

    Asigurați-vă că fiecare fir obține resursele necesare și comunică reciproc în timp util este o sarcină în sine, în cazul în care un accident poate duce la un rezultat surprinzător. Sau daca un fir schimbă date și altul îl citește in acelasi timp, ce credeți că va vedea celălalt fir? Datele actualizate sau vechi?

    Cu toate acestea, lucrătorii web nu sunt atât de ușor de înșelat. În timpul comunicării prin intermediul mesajelor, datele pe care le trimit reciproc sunt nu original, ci o copie, ceea ce înseamnă că nu acțiune aceleași date. ei treci copii ale datelor reciproc când e nevoie.

    Dar partajarea este grijuliu, iar firele multiple ar putea avea de asemenea nevoie să privească aceleași date în același timp și să le schimbe. Asa de, interzicerea partajării este un mare nu-nu. Aici este locul unde SharedArrayBuffer obiect intră în imagine. Ne va permite partajați datele binare între mai multe fire.

    SharedArrayBuffer obiect

    În loc să trecem copiile de date între fire, noi treci copii ale SharedArrayBuffer obiect. A SharedArrayBuffer obiect indică memoria în care datele sunt salvate.

    Deci, chiar și atunci când copii de SharedArrayBuffer sunt trecute între fire, ele totul va indica totuși aceeași memorie unde sunt salvate datele originale. Firele pot astfel să vizualizeze și să actualizeze datele din aceeași memorie.

    Lucrătorii Web fără memorie partajată

    Pentru a vedea cum funcționează un lucrător web fără a utiliza memoria partajată, noi creați un thread lucrător și transmiteți niște date către el.

    index.html fișierul deține scenariul principal în interiorul a etichetă, așa cum o vedeți mai jos:

     const w = lucrător nou ("worker.js"); var n = 9; w.postMessage (n); 

    worker.js fișierul poartă lucrător script:

     onmessage = (e) => console.group ("[lucrător]"); console.log ("Date primite de la firul principal:% i", e.data); console.groupEnd ();  

    Folosind codul de mai sus, primim următoarele ieșire în consola:

     [worker] Datele primite de la subiectul principal: 9 

    Puteți citi postarea mea menționată mai sus pe lucrătorii web pentru explicarea completă a codului fragmentelor de mai sus.

    Deocamdată, rețineți că datele sunt trimis înapoi și înapoi între fire folosind postMessage () metodă. Datele sunt primit pe de altă parte de către mesaj organizatorul evenimentului, ca valoare a evenimentului date proprietate.

    Acum, dacă noi schimbați datele va apărea actualizat la sfârșitul primirii? Sa vedem:

     const w = lucrător nou ("worker.js"); var n = 9; w.postMessage (n); n = 1; 

    Asa cum era de asteptat, datele au nu fost actualizat:

     [worker] Datele primite de la subiectul principal: 9 

    De ce ar fi, oricum? este doar o clonă trimisă lucrătorului din scenariul principal.

    Lucrătorii Web cu memorie partajată

    Acum o vom face folosește SharedArrayBuffer obiect în același exemplu. Putem crea un nou SharedArrayBuffer exemplu prin folosind nou cuvinte cheie. Constructorul are un parametru; A lungime în octeți, specificând dimensiunea buffer-ului.

     const w = lucrător nou ("worker.js"); buff = nou SharedArrayBuffer (1); var arr = nou Int8Array (buff); / * setarea datelor * / arr [0] = 9; / * trimiterea tamponului (copia) către lucrătorul * / w.postMessage (buff); 

    Rețineți că a SharedArrayBuffer obiect reprezintă doar o zonă de memorie partajată. La vedeți și modificați datele binare, trebuie să folosim o structură de date adecvată (a TypedArray sau a DataView obiect).

    În index.html fișierul de mai sus, un nou SharedArrayBuffer este creată, cu o lungime de numai un octet. Apoi, un nou Int8Array, care este un tip de TypedArray obiecte, este folosit pentru a setați datele la “9” în spațiul octet furnizat.

     onmessage = (e) => var arr = nou Int8Array (e.data); console.group ( '[lucrător]'); console.log ('Datele primite de la firul principal:% i', arr [0]); console.groupEnd ();  

    Int8Array este, de asemenea, utilizat la lucrător, la vizualizați datele din memoria tampon.

    valoarea așteptată apare în consola de la firul muncitorului, ceea ce ne-am dorit:

     [worker] Datele primite de la subiectul principal: 9 

    Acum hai să actualizați datele din firul principal pentru a vedea dacă schimbarea se reflectă în lucrător.

     const w = lucrător nou ("worker.js"), buff = nou SharedArrayBuffer (1); var arr = nou Int8Array (buff); / * setarea datelor * / arr [0] = 9; / * trimiterea tamponului (copia) către lucrătorul * / w.postMessage (buff); / * modificarea datelor * / arr [0] = 1;

    Și, după cum puteți vedea mai jos, actualizarea se reflectă în interiorul muncitorului!

     [worker] Datele primite din partea principală: 1 

    Dar, și codul trebuie să lucreze invers: atunci când valoarea lucrătorului se schimbă la început, acesta este trebuie, de asemenea, să fie actualizate când este imprimat din firul principal.

    În acest caz, codul nostru arată astfel:

     onmessage = (e) => var arr = nou Int8Array (e.data); console.group ( '[lucrător]'); console.log ('Datele primite de la firul principal:% i', arr [0]); console.groupEnd (); / * modificarea datelor * / arr [0] = 7; / * postarea la firul principal * / postMessage ("); 

    datele sunt modificate în lucrătoare si un mesajul gol este postat pe firul principal semnalând că datele din memoria tampon au fost schimbate și sunt pregătite pentru ca firul principal să fie afișat.

     const w = lucrător nou ("worker.js"), buff = nou SharedArrayBuffer (1); var arr = nou Int8Array (buff); / * setarea datelor * / arr [0] = 9; / * trimiterea tamponului (copia) către lucrătorul * / w.postMessage (buff); / * modificarea datelor * / arr [0] = 1; / * tipărirea datelor după ce lucrătorul le-a schimbat * / w.onmessage = (e) => console.group ('[main]'); console.log ('Datele actualizate primite de la firul lucrătorului:% i', arr [0]); console.groupEnd ();  

    Și, și asta funcționează! Datele din buffer sunt identice cu datele din interiorul lucrătorului.

     [lucrător] Datele primite de la atacul principal: 1 [principală] Datele actualizate primite de la firul lucrătorului: 7 

    Valoarea este actualizat în ambele cazuri; atât firele principale cât și lucrătorii vizualizează și modifică aceleași date.

    Cuvintele finale

    După cum am menționat mai devreme, folosind memoria partajată în JavaScript nu este lipsită de dezavantaje. Depinde de dezvoltatori să se asigure că secvența de execuție se întâmplă așa cum a fost prevăzută și nici două fire nu mai concurează pentru a obține aceleași date, deoarece nimeni nu știe cine va lua trofeul.

    Dacă vă interesează mai mult memoria partajată, consultați documentația Atomics obiect. Obiectul atomic vă poate ajuta cu unele dintre greutățile, prin reducerea naturii imprevizibile a citirii / scriinței din memoria partajată.