SharedArrayBuffer sa JavaScript
Ipinaliliwanag ng artikulong ito ang SharedArrayBuffer
sa JavaScript.
Magbibigay kami ng detalyadong paliwanag tungkol sa mga saligan ng SharedArrayBuffer
, kung paano ito gamitin, mga tiyak na paggamit, at mga konsiderasyong pangseguridad.
YouTube Video
SharedArrayBuffer sa JavaScript
Ang SharedArrayBuffer
ay isang makapangyarihang tool sa JavaScript para sa pagbabahagi ng memorya sa pagitan ng maraming thread. Lalo na kapag pinagsama ito sa Web Workers, nagbibigay-daan ito sa parallel processing, kaya epektibo ito para sa mga computation-intensive na gawain at mga application na nangangailangan ng kakayahang real-time.
Ano ang SharedArrayBuffer?
Ang SharedArrayBuffer
ay nagbibigay ng memory buffer sa JavaScript na nagpapahintulot sa pagbabahagi ng binary data sa pagitan ng maraming thread (karamihan ay Web Workers). Ang isang karaniwang ArrayBuffer
ay nangangailangan ng pagkopya sa pagitan ng main thread at mga worker, ngunit pinapayagan ng SharedArrayBuffer
ang direktang pagbabahagi ng memorya nang hindi kinakailangan ng pagkopya, kaya't lubos nitong pinapabuti ang pagganap.
Mga Tampok
- Pinagsasaluhang Memorya Pinapayagan nito ang maraming thread na gumana sa iisang memory space.
- Pagpapabuti ng Pagganap Dahil maaring hindi na kopyahin, nababawasan ang overhead kapag pinoproseso ang malaking halaga ng datos.
- Pag-sabay ng mga Thread
Maaari mo itong gamitin kasabay ng
Atomics
para magsagawa ng synchronisasyon at maiwasan ang mga salungatan kapag uma-access ng memorya.
Pangunahing Halimbawa ng Paggamit
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
Sa halimbawang ito, lilikha tayo ng 16-byte na lugar ng memorya gamit ang SharedArrayBuffer
at ituturing ang lugar na iyon bilang isang Int32Array
. Ang memory buffer na ito ay maaaring ibahagi sa pagitan ng maraming thread.
Paggamit Kasama ng Web Workers
Ang tunay na halaga ng SharedArrayBuffer
ay naipapakita kapag ginamit ito kasabay ng Web Workers. Ang sumusunod na code ay isang halimbawa ng paggamit ng shared memory sa pagitan ng main thread at ng worker.
Sa Main Thread
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]);
Sa Worker 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};
- Sa halimbawang ito, ang main thread ay lumikha ng shared buffer at ipinasa ito sa worker. Maaaring ma-access ng worker ang buffer na ito upang basahin at baguhin ang mga halaga. Sa ganitong paraan, maaaring ibahagi ang data sa pagitan ng mga thread nang walang pagkopya.
Dalawang Paraang Kumpirmasyon ng Update
Sa paggamit ng SharedArrayBuffer
, parehong makakabasa at makakasulat sa parehong memorya ang main thread at mga worker, kaya nagiging posible ang dalawang paraang kumpirmasyon ng update. Narito ang isang halimbawa kung saan ang main thread ang nagtatakda ng halaga, binabago ito ng worker, at pagkatapos ay sine-check ng main thread ang update.
Sa Main Thread
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};
Sa Worker 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};
- Sa halimbawang ito, unang isinulat ng main thread ang halagang
100
, at pagkatapos basahin ito ng worker, papalitan niya ito ng200
. Pagkatapos nito, inaabisuhan ng worker ang main thread, at muling binabasa ng main thread ang pinagsasaluhang memorya para kumpirmahin ang update. Sa ganitong paraan, ang pagsasama ng mga notipikasyon ay nagpapahintulot ng dalawang paraang kumpirmasyon ng update.
Pag-synchronize gamit ang Atomics
Kapag gumagamit ng shared memory, kailangang maging maingat sa mga kondisyon ng data race at mga pagkakamaling hindi magkakatugma. Kapag ang maraming thread ay sabay-sabay na nag-a-access sa parehong memory, maaaring mangyari ang salungatan. Upang maiwasan ito, ginagamit ng JavaScript ang Atomics
object para sa synchronization.
Halimbawa, upang ligtas na madagdagan ang isang counter gamit ang maraming thread, maaari mong gamitin ang Atomics
upang maiwasan ang salungatan.
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
Ang Atomics.add
ay nagdaragdag ng halaga sa isang partikular na index nang walang salungatan at ibinabalik ang bagong halaga. Ang operasyong ito ay garantisadong walang salungatan sa ibang mga thread. Ang Atomics.load
ay ginagamit din upang ligtas na basahin ang mga halaga mula sa shared memory.
Paghihintay at Pag-abiso Gamit ang Atomics.wait
at Atomics.notify
Kapag gumagamit ng SharedArrayBuffer
, may mga pagkakataon na kailangang maghintay ang isang worker hanggang matupad ang isang kundisyon, at kapag natugunan na ito ng ibang worker, kailangang i-abiso ang naghihintay na worker. Sa ganoong mga kaso, kapaki-pakinabang ang Atomics.wait
at Atomics.notify
.
Ang Atomics.wait
ay nagba-block ng thread hanggang sa magbago ang halaga sa isang partikular na index sa pinagsasaluhang memorya, habang inaabiso naman ng Atomics.notify
sa mga naghihintay na thread na maaari na silang magpatuloy. Ito ay nagpapahintulot ng ligtas na paghihintay at pag-abiso sa pagitan ng maraming worker. Gayunpaman, ang Atomics.wait
ay hindi maaaring gamitin sa pangunahing thread at tanging magagamit lamang sa loob ng mga worker.
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};
- Sa pangunahing thread, ang
SharedArrayBuffer
ay nililikha bilang shared memory at ikino-convert sa isangInt32Array
na may iisang elemento lamang. Ang iisang integer slot na ito ay ginagamit bilang signal upang magsabay-sabay ang mga worker. Sunod, dalawang worker ang nililikha at binibigyan ng kani-kanilang gawain gamit angname
property:waiter
(ang naghihintay) atnotifier
(ang nagbibigay-abiso). Panghuli, ang shared buffer ay ipinapasa sa parehong worker, at ang mgaonmessage
handler ay nilalagay upang matanggap ang mga mensahe mula sa bawat worker.
Sa Worker 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!
- Sa halimbawang ito, ang
waiter
na worker ay nananatiling naghihintay gamit angAtomics.wait
hangga't ang value sa index0
ay0
. Sa kabilang banda, kapag binago ngnotifier
na worker ang value sa123
gamit angAtomics.store
at tinawag angAtomics.notify
, magpapatuloy angwaiter
na worker at makukuha na niya ang bagong value. Dahil dito, maaari nang makamit ang mahusay at ligtas na paghihintay at pagbibigay-abiso sa pagitan ng mga thread.
Mga Gamit ng SharedArrayBuffer
Ang SharedArrayBuffer
ay partikular na kapaki-pakinabang sa mga sumusunod na kaso ng paggamit:.
- Proseso sa Real-Time Ito ay angkop para sa mga aplikasyon na nangangailangan ng mababang latency, tulad ng audio at video processing o mga game engine, kung saan kailangang agad na maibahagi ang data sa pagitan ng mga thread.
- Parallel na Pagkalkula
Kapag maraming datos ang pinoproseso sabay-sabay gamit ang maraming thread, ang paggamit ng
SharedArrayBuffer
ay nakakaiwas sa pagkopya ng memorya at maaaring magpabuti ng pagganap. - Pagkatuto ng Makina Sa pamamagitan ng parallelization ng mga gawain tulad ng preprocessing at inference ng datos, nagiging posible ang episyenteng pagkalkula.
Mga Pagsasaalang-alang para sa Seguridad
Ang SharedArrayBuffer
ay isang makapangyarihang tampok, ngunit nagdadala rin ito ng mga panganib sa seguridad. Partikular, ang mga alalahanin tungkol sa side-channel attacks tulad ng Spectre
ay pansamantalang huminto sa suporta nito. Upang mabawasan ang kahinaang ito, ipinatupad ng mga browser ang mga sumusunod na hakbang:.
- Pagkakahiwalay ng Site
Ang mga site na pinapahintulutan ang paggamit ng
SharedArrayBuffer
ay tatakbo sa isang proseso na ganap na nakahiwalay sa ibang mga site. - Patakaran para sa Cross-Origin na Resources
Para magamit ang
SharedArrayBuffer
, kailangang maayos na itakda ang mga header naCross-Origin-Opener-Policy
atCross-Origin-Embedder-Policy
.
Halimbawa, sa pamamagitan ng pag-set ng mga header tulad ng sumusunod, nagiging posible ang paggamit ng SharedArrayBuffer
:.
1Cross-Origin-Opener-Policy: same-origin
2Cross-Origin-Embedder-Policy: require-corp
Pinipigilan nito ang mga panlabas na mapagkukunan mula sa panghihimasok sa kasalukuyang nilalaman at pinapabuti ang seguridad.
Buod
Ang SharedArrayBuffer
ay isang napakalakas na kasangkapan para sa pagbabahagi ng memory sa pagitan ng maraming thread. Ito ay isang mahalagang teknolohiya para sa pagpapahusay ng pagganap, at ang mga epekto nito ay partikular na makikita sa mga larangan ng real-time na pagpoproseso at parallel computing. Gayunpaman, may mga panganib din ito sa seguridad, kaya't mahalaga ang wastong kumpigurasyon at pagsabay.
Sa paggamit ng SharedArrayBuffer
, makakagawa ka ng mas abante at mas mataas na pagganap na mga web application.
Maaari mong sundan ang artikulo sa itaas gamit ang Visual Studio Code sa aming YouTube channel. Paki-check din ang aming YouTube channel.