SharedArrayBuffer dalam JavaScript

SharedArrayBuffer dalam JavaScript

Artikel ini menjelaskan SharedArrayBuffer dalam JavaScript.

Kami akan memberikan penjelasan rinci tentang dasar-dasar SharedArrayBuffer, cara menggunakannya, kasus penggunaan spesifik, dan pertimbangan keamanan.

YouTube Video

SharedArrayBuffer dalam JavaScript

SharedArrayBuffer adalah alat yang kuat dalam JavaScript untuk berbagi memori antara beberapa thread. Terutama jika dikombinasikan dengan Web Workers, hal ini memungkinkan pemrosesan paralel, sehingga efektif untuk tugas intensif komputasi dan aplikasi yang memerlukan kemampuan real-time.

Apa itu SharedArrayBuffer?

SharedArrayBuffer menyediakan buffer memori dalam JavaScript yang memungkinkan berbagi data biner antara beberapa thread (terutama Web Workers). ArrayBuffer biasa memerlukan penyalinan antara thread utama dan worker, tetapi SharedArrayBuffer memungkinkan berbagi memori secara langsung tanpa penyalinan, sehingga secara signifikan meningkatkan kinerja.

Fitur

  • Memori Bersama Ini memungkinkan beberapa thread untuk bekerja dengan ruang memori yang sama.
  • Peningkatan Performa Karena penyalinan dapat dihilangkan, overhead berkurang saat memproses data dalam jumlah besar.
  • Sinkronisasi Thread Anda dapat menggunakannya bersama dengan Atomics untuk melakukan sinkronisasi guna menghindari konflik saat mengakses memori.

Contoh Penggunaan Dasar

 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

Dalam contoh ini, kita membuat area memori 16-byte menggunakan SharedArrayBuffer dan memperlakukan area memori tersebut sebagai Int32Array. Buffer memori ini dapat dibagi di antara beberapa thread.

Menggunakan dengan Web Workers

Nilai sebenarnya dari SharedArrayBuffer ditunjukkan ketika digunakan bersama dengan Web Workers. Kode berikut adalah contoh penggunaan memori bersama antara thread utama dan worker.

Di Thread Utama

 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]);

Di Sisi Worker (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};
  • Dalam contoh ini, thread utama membuat buffer bersama dan menyerahkannya ke worker. Worker dapat mengakses buffer ini untuk membaca dan memodifikasi nilai. Dengan cara ini, data dapat dibagi di antara thread tanpa penyalinan.

Konfirmasi Pembaruan Dua Arah

Dengan menggunakan SharedArrayBuffer, baik thread utama maupun worker dapat membaca dan menulis ke memori yang sama, memungkinkan konfirmasi pembaruan dua arah. Di bawah ini adalah contoh di mana thread utama menetapkan sebuah nilai, worker mengubah nilai tersebut, lalu thread utama memeriksa pembaruan tersebut.

Di Thread Utama

 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};

Di Sisi Worker (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};
  • Dalam contoh ini, thread utama menulis nilai 100 terlebih dahulu, dan setelah worker membacanya, worker menulis ulang menjadi 200. Setelah itu, worker memberi tahu thread utama, dan thread utama membaca memori bersama lagi untuk mengonfirmasi pembaruan. Dengan cara ini, kombinasi notifikasi memungkinkan konfirmasi pembaruan dua arah.

Sinkronisasi dengan Atomics

Ketika menggunakan memori bersama, seseorang harus berhati-hati terhadap kondisi data race dan inkonsistensi. Ketika beberapa thread mengakses memori yang sama secara bersamaan, konflik dapat terjadi. Untuk mencegah ini, JavaScript menggunakan objek Atomics untuk sinkronisasi.

Sebagai contoh, untuk meningkatkan penghitung dengan aman melalui beberapa thread, Anda dapat menggunakan Atomics untuk mencegah konflik.

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

Atomics.add menambah nilai di indeks tertentu secara atomik dan mengembalikan nilai baru. Operasi ini dijamin bebas konflik dengan thread lainnya. Atomics.load juga digunakan untuk membaca nilai dari memori bersama dengan aman.

Menunggu dan Notifikasi Menggunakan Atomics.wait dan Atomics.notify

Saat menggunakan SharedArrayBuffer, ada situasi di mana worker harus menunggu hingga kondisi tertentu terpenuhi, dan setelah worker lain memenuhi kondisi tersebut, worker tersebut harus memberi tahu worker yang sedang menunggu. Dalam kasus seperti itu, Atomics.wait dan Atomics.notify sangat berguna.

Atomics.wait memblokir sebuah thread hingga nilai di indeks tertentu dalam memori bersama berubah, sedangkan Atomics.notify memberi tahu thread yang sedang menunggu bahwa mereka dapat melanjutkan. Ini memungkinkan proses menunggu dan notifikasi yang aman di antara beberapa worker. Namun, Atomics.wait tidak dapat digunakan di thread utama dan hanya tersedia di dalam 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};
  • Di thread utama, sebuah SharedArrayBuffer dibuat sebagai memori bersama dan diubah menjadi Int32Array dengan hanya satu elemen. Slot integer tunggal ini digunakan sebagai sinyal untuk melakukan sinkronisasi antara worker. Selanjutnya, dua worker dibuat, dan masing-masing diberikan peran menggunakan properti name: waiter (sebagai penunggu) dan notifier (sebagai pemberi notifikasi). Akhirnya, buffer yang dibagikan diteruskan ke kedua worker, dan handler onmessage disiapkan agar pesan yang dikirim dari tiap worker dapat diterima.

Di Sisi Worker (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!
  • Pada contoh ini, worker waiter tetap berada dalam keadaan menunggu menggunakan Atomics.wait selama nilai pada indeks 0 adalah 0. Di sisi lain, ketika worker notifier mengubah nilainya menjadi 123 dengan Atomics.store dan memanggil Atomics.notify, worker waiter akan melanjutkan dan dapat mendapatkan nilai terbaru. Dengan cara ini, proses menunggu dan notifikasi antar thread yang efisien dan aman dapat dicapai.

Penggunaan Kasus untuk SharedArrayBuffer

SharedArrayBuffer sangat berguna untuk penggunaan kasus berikut:.

  • Pemrosesan Waktu Nyata Ini cocok untuk aplikasi yang memerlukan latensi rendah, seperti pemrosesan audio dan video atau engine game, di mana data perlu dibagikan secara instan antar thread.
  • Komputasi Paralel Saat memproses data dalam jumlah besar secara bersamaan dengan beberapa thread, penggunaan SharedArrayBuffer menghindari penyalinan memori dan dapat meningkatkan performa.
  • Pembelajaran Mesin Dengan memparalelkan tugas-tugas seperti praproses data dan inferensi, komputasi yang efisien menjadi mungkin.

Pertimbangan Keamanan

SharedArrayBuffer adalah fitur yang kuat, tetapi juga membawa risiko keamanan. Terutama, kekhawatiran tentang serangan side-channel seperti Spectre telah menghentikan dukungannya untuk sementara waktu. Untuk mengurangi kerentanan ini, browser telah mengimplementasikan langkah-langkah berikut:.

  • Isolasi Situs Situs yang mengizinkan penggunaan SharedArrayBuffer akan berjalan dalam proses yang sepenuhnya terisolasi dari situs lain.
  • Kebijakan Sumber Daya Cross-Origin Untuk menggunakan SharedArrayBuffer, header Cross-Origin-Opener-Policy dan Cross-Origin-Embedder-Policy harus diatur dengan benar.

Sebagai contoh, dengan mengatur header seperti berikut, penggunaan SharedArrayBuffer menjadi mungkin:.

1Cross-Origin-Opener-Policy: same-origin
2Cross-Origin-Embedder-Policy: require-corp

Ini mencegah sumber daya eksternal mengganggu konten saat ini dan meningkatkan keamanan.

Ringkasan

SharedArrayBuffer adalah alat yang sangat kuat untuk berbagi memori antar beberapa thread. Ini adalah teknologi penting untuk meningkatkan kinerja, dan efeknya sangat terlihat terutama dalam bidang pemrosesan real-time dan komputasi paralel. Namun, ini juga melibatkan risiko keamanan, sehingga konfigurasi dan sinkronisasi yang benar sangat penting.

Dengan memanfaatkan SharedArrayBuffer, Anda dapat membangun aplikasi web yang lebih canggih dan berkinerja tinggi.

Anda dapat mengikuti artikel di atas menggunakan Visual Studio Code di saluran YouTube kami. Silakan periksa juga saluran YouTube kami.

YouTube Video