JavaScript'te SharedArrayBuffer

JavaScript'te SharedArrayBuffer

Bu makale, JavaScript'teki SharedArrayBuffer kavramını açıklar.

SharedArrayBuffer'ın temelleri, nasıl kullanılacağı, belirli kullanım durumları ve güvenlik hususları hakkında ayrıntılı bir açıklama sunacağız.

YouTube Video

JavaScript'te SharedArrayBuffer

SharedArrayBuffer, JavaScript'te birden fazla thread arasında bellek paylaşımı yapmak için güçlü bir araçtır. Özellikle Web Workers ile birlikte kullanıldığında paralel işlemeyi sağlar, bu da onu hesaplama yoğun görevler ve gerçek zamanlı özellikler gerektiren uygulamalar için etkili kılar.

SharedArrayBuffer nedir?

SharedArrayBuffer, JavaScript'te birden fazla thread (öncelikle Web Workers) arasında ikili verilerin paylaşılmasına olanak tanıyan bir bellek tamponu sağlar. Standart bir ArrayBuffer, ana thread ile worker'lar arasında kopyalama yapılmasını gerektirirken, SharedArrayBuffer kopyalama işlemi olmadan doğrudan bellek paylaşımına izin verir ve böylelikle performansı önemli ölçüde artırır.

Özellikler

  • Paylaşılan Bellek Birden fazla iş parçacığının aynı bellek alanında çalışmasına olanak tanır.
  • Performans İyileştirmesi Kopyalama atlanabildiğinden, büyük miktarda veri işlenirken ek yük azaltılır.
  • İş Parçacığı Senkronizasyonu Belleğe erişimde çakışmaları önlemek için, Atomics ile birlikte kullanarak senkronizasyon sağlayabilirsiniz.

Temel Kullanım Örneği

 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

Bu örnekte, SharedArrayBuffer kullanarak 16 baytlık bir bellek alanı oluşturuyoruz ve bu bellek alanını Int32Array olarak değerlendiriyoruz. Bu bellek tamponu birden fazla thread arasında paylaşılabilir.

Web Workers ile Kullanım

SharedArrayBuffer'ın gerçek değeri, Web Workers ile birlikte kullanıldığında ortaya çıkar. Aşağıdaki kod, ana thread ile bir worker arasında paylaşılan bellek kullanımına bir örnektir.

Ana Thread Üzerinde

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

Worker Tarafında (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};
  • Bu örnekte, ana thread bir paylaşılan tampon oluşturur ve bunu worker'a iletir. Worker, bu tampon belleğe erişerek değerleri okuyabilir ve değiştirebilir. Bu şekilde, veriler thread'ler arasında kopyalama olmadan paylaşılabilir.

Çift Yönlü Güncelleme Onayı

SharedArrayBuffer kullanarak, ana iş parçacığı ve çalışanlar aynı belleğe okuyup yazabilir ve böylece çift yönlü güncelleme onayı sağlanır. Aşağıda, ana iş parçacığının bir değeri ayarladığı, bir çalışanın bu değeri değiştirdiği ve ardından ana iş parçacığının güncellemeyi kontrol ettiği bir örnek bulunmaktadır.

Ana Thread Üzerinde

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

Worker Tarafında (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};
  • Bu örnekte, ana iş parçacığı önce 100 değerini yazar ve çalışan bu değeri okuduktan sonra, değeri 200 olarak değiştirir. Bundan sonra çalışan ana iş parçacığını bilgilendirir ve ana iş parçacığı, güncellemeyi onaylamak için paylaşılan belleği tekrar okur. Bu şekilde, bildirimlerin birleştirilmesiyle çift yönlü güncelleme onayı sağlanır.

Atomics ile Senkronizasyon

Paylaşılan bellek kullanırken, veri yarış durumlarına ve tutarsızlıklara karşı dikkatli olunmalıdır. Birden fazla iş parçacığı aynı belleğe aynı anda eriştiğinde, çatışmalar oluşabilir. Bunu önlemek için JavaScript, senkronizasyon için Atomics nesnesini kullanır.

Örneğin, bir sayacı birden fazla iş parçacığıyla güvenle artırmak için çatışmaları önlemek adına Atomics kullanabilirsiniz.

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, belirli bir indeksteki değeri atomik olarak artırır ve yeni değeri döndürür. Bu işlem, diğer iş parçacıklarıyla çatışmasız bir şekilde gerçekleştirileceği garanti edilir. Atomics.load, paylaşılan bellekten değerleri güvenli bir şekilde okumak için de kullanılır.

Atomics.wait ve Atomics.notify Kullanarak Bekleme ve Bildirim

SharedArrayBuffer kullanırken, bir çalışanın belirli bir koşulun gerçekleşmesini beklemesi gereken durumlar olabilir ve başka bir çalışan bu koşulu yerine getirdiğinde, bekleyen çalışanı bilgilendirmesi gerekir. Bu gibi durumlarda, Atomics.wait ve Atomics.notify kullanışlıdır.

Atomics.wait, paylaşılan bellekteki belirli bir indeksteki değer değişene kadar bir iş parçacığını bloke ederken, Atomics.notify bekleyen iş parçacıklarına işlemeye devam etmeleri gerektiğini bildirir. Bu, birden fazla çalışan arasında güvenli bekleme ve bildirim sağlar. Atomics.wait ise ana iş parçacığında kullanılamaz ve yalnızca worker içinde kullanılabilir.

 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};
  • Ana iş parçacığında, paylaşılan bir bellek olarak bir SharedArrayBuffer oluşturulur ve bu, yalnızca bir elemanı olan bir Int32Array'e dönüştürülür. Bu tek tam sayı yuvası, workerlar arasında senkronizasyon sinyali olarak kullanılır. Sonrasında, iki worker oluşturulur ve her birine name özelliği kullanılarak bir rol atanır: waiter (bekleyen rolü) ve notifier (bildiren rolü). Son olarak, paylaşılan buffer her iki workera da iletilir ve her worker'dan gönderilen mesajların alınabilmesi için onmessage işlemcileri kurulur.

Worker Tarafında (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!
  • Bu örnekte, waiter worker'ı, 0 indisindeki değer 0 olduğu sürece Atomics.wait kullanarak bekleme durumunda kalır. Diğer yandan, notifier worker'ı değeri Atomics.store ile 123 olarak değiştirdiğinde ve Atomics.notify çağrıldığında, waiter worker'ı işlemini sürdürür ve güncellenmiş değeri alabilir. Böylece, iş parçacıkları arasında etkili ve güvenli bekleme ile bildirim sağlanabilir.

SharedArrayBuffer Kullanım Alanları

SharedArrayBuffer özellikle aşağıdaki kullanım durumlarında faydalıdır:.

  • Gerçek Zamanlı İşleme Verinin iş parçacıkları arasında anında paylaşılması gereken, ses ve video işleme veya oyun motorları gibi düşük gecikme gerektiren uygulamalar için uygundur.
  • Paralel Hesaplama Birden fazla iş parçacığı ile büyük miktarda veriyi aynı anda işlerken, SharedArrayBuffer kullanmak bellek kopyalamayı önler ve performansı artırabilir.
  • Makine Öğrenimi Veri ön işleme ve çıkarım gibi görevleri paralel hale getirerek verimli hesaplama mümkün olur.

Güvenlik Hususları

SharedArrayBuffer güçlü bir özelliktir ancak aynı zamanda güvenlik riskleri taşır. Özellikle Spectre gibi yan kanal saldırıları ile ilgili endişeler, desteğinin geçici olarak durdurulmasına neden olmuştur. Bu güvenlik açığını hafifletmek için tarayıcılar aşağıdaki önlemleri uygulamıştır:.

  • Site İzolasyonu SharedArrayBuffer kullanımına izin veren siteler, diğer sitelerden tamamen izole edilmiş bir süreçte çalıştırılır.
  • Çapraz-Kaynak Kaynak Politikası SharedArrayBuffer kullanmak için, Cross-Origin-Opener-Policy ve Cross-Origin-Embedder-Policy başlıklarının doğru şekilde ayarlanmış olması gerekir.

Örneğin, aşağıdaki gibi başlıklar ayarlandığında SharedArrayBuffer kullanımı mümkün olur:.

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

Bu, harici kaynakların mevcut içerikle etkileşime girmesini önler ve güvenliği artırır.

Özet

SharedArrayBuffer, birden fazla iş parçacığı arasında bellek paylaşımı için çok güçlü bir araçtır. Performansı artırmak için gerekli bir teknolojidir ve etkileri özellikle gerçek zamanlı işleme ve paralel hesaplama alanlarında belirgindir. Bununla birlikte, güvenlik risklerini de içerir, bu nedenle doğru yapılandırma ve senkronizasyon önemlidir.

SharedArrayBuffer kullanarak daha gelişmiş ve yüksek performanslı web uygulamaları geliştirebilirsiniz.

Yukarıdaki makaleyi, YouTube kanalımızda Visual Studio Code'u kullanarak takip edebilirsiniz. Lütfen YouTube kanalını da kontrol edin.

YouTube Video