SharedArrayBuffer dalam JavaScript

SharedArrayBuffer dalam JavaScript

Artikel ini menerangkan SharedArrayBuffer dalam JavaScript.

Kami akan memberikan penjelasan terperinci mengenai asas SharedArrayBuffer, cara penggunaannya, kes-kes penggunaan tertentu, dan pertimbangan keselamatan.

YouTube Video

SharedArrayBuffer dalam JavaScript

SharedArrayBuffer adalah alat yang berkuasa dalam JavaScript untuk berkongsi memori antara pelbagai urutan. Terutamanya apabila digabungkan dengan Web Workers, ia membolehkan pemprosesan selari, menjadikannya berkesan untuk tugas berat pengiraan dan aplikasi yang memerlukan keupayaan masa nyata.

Apakah itu SharedArrayBuffer?

SharedArrayBuffer menyediakan penampan memori dalam JavaScript yang membolehkan perkongsian data binari antara pelbagai urutan (terutamanya Web Workers). ArrayBuffer biasa memerlukan salinan antara urutan utama dan pekerja, tetapi SharedArrayBuffer membolehkan perkongsian memori terus tanpa salinan, sekali gus meningkatkan prestasi dengan ketara.

Ciri-ciri

  • Memori Berkongsi Ia membolehkan berbilang benang bekerja dalam ruang memori yang sama.
  • Penambahbaikan Prestasi Memandangkan penyalinan boleh diabaikan, lebihan proses dikurangkan apabila memproses sejumlah besar data.
  • Penyegerakan Benang Anda boleh menggunakannya bersama-sama dengan Atomics untuk melakukan penyegerakan bagi mengelakkan konflik semasa mengakses memori.

Contoh Penggunaan Asas

 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, kami mencipta kawasan memori 16-byte menggunakan SharedArrayBuffer dan menganggap kawasan memori tersebut sebagai Int32Array. Penampan memori ini boleh dikongsi di antara pelbagai urutan.

Menggunakan dengan Web Workers

Nilai sebenar SharedArrayBuffer ditunjukkan apabila digunakan bersama-sama dengan Web Workers. Kod berikut adalah contoh penggunaan memori yang dikongsi antara urutan utama dan pekerja.

Pada Urutan 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 Pihak Pekerja (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, urutan utama mencipta penampan yang dikongsi dan menyerahkannya kepada pekerja. Pekerja boleh mengakses penampan ini untuk membaca dan mengubah nilai. Dengan cara ini, data boleh dikongsi antara urutan tanpa salinan.

Pengesahan Kemaskini Dua Hala

Dengan menggunakan SharedArrayBuffer, kedua-dua benang utama dan pekerja boleh membaca dan menulis pada memori yang sama, membolehkan pengesahan kemaskini dua hala. Di bawah ialah contoh di mana benang utama menetapkan satu nilai, seorang pekerja mengubah nilai itu, dan kemudian benang utama menyemak kemaskini tersebut.

Pada Urutan 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 Pihak Pekerja (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, benang utama menulis nilai 100 terlebih dahulu, dan selepas pekerja membaca nilai tersebut, ia ditulis semula menjadi 200. Selepas itu, pekerja memaklumkan kepada benang utama, dan benang utama membaca memori berkongsi sekali lagi untuk mengesahkan kemaskini. Dengan cara ini, gabungan pemberitahuan membolehkan pengesahan kemaskini dua hala.

Penyelarasan dengan Atomics

Apabila menggunakan memori dikongsi, seseorang mesti berhati-hati terhadap keadaan perlumbaan data dan ketidakkonsistenan. Apabila beberapa utas mengakses memori yang sama secara serentak, konflik boleh berlaku. Untuk mengelakkan ini, JavaScript menggunakan objek Atomics untuk penyelarasan.

Sebagai contoh, untuk meningkatkan penunjuk kiraan dengan selamat menggunakan pelbagai utas, anda boleh menggunakan Atomics untuk mengelakkan 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 pada indeks tertentu secara atomik dan mengembalikan nilai baru. Operasi ini dijamin bebas konflik dengan utas-utas lain. Atomics.load juga digunakan untuk membaca nilai dengan selamat daripada memori kongsi.

Menunggu dan Pemberitahuan Menggunakan Atomics.wait dan Atomics.notify

Apabila menggunakan SharedArrayBuffer, terdapat situasi di mana seorang pekerja perlu menunggu sehingga satu keadaan tertentu dicapai, dan selepas seorang lagi pekerja memenuhi keadaan tersebut, pekerja itu harus memaklumkan kepada pekerja yang sedang menunggu. Dalam kes seperti ini, Atomics.wait dan Atomics.notify adalah berguna.

Atomics.wait akan menyekat sesuatu benang sehingga nilai pada indeks tertentu dalam memori berkongsi berubah, manakala Atomics.notify memaklumkan benang yang menunggu bahawa mereka boleh meneruskan. Ini membolehkan proses menunggu dan pemberitahuan dengan selamat di antara beberapa pekerja. Walau bagaimanapun, Atomics.wait tidak boleh digunakan pada utas utama dan hanya tersedia di dalam pekerja (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};
  • Pada utas utama, SharedArrayBuffer dicipta sebagai memori kongsi dan ditukar menjadi Int32Array dengan hanya satu elemen. Slot integer tunggal ini digunakan sebagai isyarat untuk menyegerakkan antara pekerja (worker). Seterusnya, dua pekerja (worker) dicipta, dan setiap satu diberikan peranan menggunakan sifat name: waiter (peranan menunggu) dan notifier (peranan memberitahu). Akhir sekali, penimbal kongsi diberikan kepada kedua-dua pekerja, dan pengendali onmessage disediakan supaya mesej yang dihantar daripada setiap pekerja dapat diterima.

Di Pihak Pekerja (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!
  • Dalam contoh ini, pekerja waiter akan kekal dalam keadaan menunggu menggunakan Atomics.wait selagi nilai pada indeks 0 adalah 0. Sebaliknya, apabila pekerja notifier menukar nilai kepada 123 dengan Atomics.store dan memanggil Atomics.notify, pekerja waiter akan menyambung semula dan boleh mendapatkan nilai terkini. Dengan ini, penantian dan pemberitahuan antara utas yang cekap dan selamat dapat dicapai.

Kes Penggunaan untuk SharedArrayBuffer

SharedArrayBuffer amat berguna untuk kes penggunaan berikut:.

  • Pemprosesan Masa Nyata Ia sesuai untuk aplikasi yang memerlukan kependaman yang rendah, seperti pemprosesan audio dan video atau enjin permainan, di mana data perlu dikongsi serta-merta antara benang.
  • Pengkomputeran Selari Apabila memproses sejumlah besar data secara serentak dengan berbilang benang, penggunaan SharedArrayBuffer dapat mengelakkan penyalinan memori dan meningkatkan prestasi.
  • Pembelajaran Mesin Dengan menjalankan tugas-tugas seperti prapemprosesan data dan inferens secara selari, pengiraan menjadi lebih cekap.

Pertimbangan Keselamatan

SharedArrayBuffer adalah ciri yang berkuasa, tetapi ia juga melibatkan risiko keselamatan. Secara khusus, kebimbangan mengenai serangan saluran sisi seperti Spectre telah menghentikan sementara sokongannya. Untuk mengurangkan kerentanan ini, pelayar telah melaksanakan langkah-langkah berikut:.

  • Pengasingan Laman Laman yang membenarkan penggunaan SharedArrayBuffer akan berjalan dalam proses yang benar-benar terasing daripada laman lain.
  • Dasar Sumber Lintas Asal Untuk menggunakan SharedArrayBuffer, pengepala Cross-Origin-Opener-Policy dan Cross-Origin-Embedder-Policy mesti disetkan dengan betul.

Sebagai contoh, dengan menetapkan pengepala seperti berikut, penggunaan SharedArrayBuffer menjadi mungkin:.

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

Ini menghalang sumber luar daripada mengganggu kandungan semasa dan meningkatkan keselamatan.

Ringkasan

SharedArrayBuffer adalah alat yang sangat berkuasa untuk berkongsi memori antara pelbagai utas. Ia adalah teknologi penting untuk meningkatkan prestasi, dan kesannya amat ketara dalam bidang pemprosesan masa nyata dan pengkomputeran selari. Walau bagaimanapun, ia juga melibatkan risiko keselamatan, jadi konfigurasi dan penyelarasan yang betul adalah penting.

Dengan memanfaatkan SharedArrayBuffer, anda boleh membina aplikasi web yang lebih maju dan berprestasi tinggi.

Anda boleh mengikuti artikel di atas menggunakan Visual Studio Code di saluran YouTube kami. Sila lihat juga saluran YouTube kami.

YouTube Video