`TypeScript`teki `SharedArrayBuffer`
Bu makale, TypeScript'teki SharedArrayBuffer'ı açıklar.
Uygulamalı örneklerle TypeScript'te SharedArrayBufferı açıklayacağız.
YouTube Video
TypeScriptteki SharedArrayBuffer
SharedArrayBuffer, aynı bellek alanının birden çok iş parçacığı arasında, örneğin Web Workers gibi, paylaşılması için bir mekanizmadır.. Atomics` ile birlikte kullanıldığında veri yarışmalarını yönetebilir ve düşük gecikmeli paylaşımlı bellek işlemleri yapabilirsiniz.
Önkoşullar ve Notlar
Tarayıcıda SharedArrayBuffer kullanırken, çapraz kaynak izolasyonu olarak bilinen güvenlik gereksinimlerini karşılamak için COOP ve COEP başlıkları gereklidir. Node.js'te, paylaşımlı bellek worker_threads ile nispeten kolay şekilde yönetilebilir.
Temel Kavramlar
SharedArrayBuffer, sabit uzunlukta bayt dizisini temsil eden bir nesnedir ve sayıları TypedArray ve benzeri görünümler üzerinden okuyabilir ve yazabilirsiniz. Basit okuma/yazma işlemleri senkronize değildir, bu nedenle atomik işlemleri garantiye almak ve eşgüdüm için wait ile notify gibi mekanizmaları kullanmak üzere Atomics API'sini kullanırsınız.
Basit Sayaç (Tarayıcı sürümü)
Bu örnekte, ana iş parçacığı bir SharedArrayBuffer oluşturur ve bunu bir Web Workera aktarır; her ikisi de paylaşılan bir sayacı artırır. Bu, en basit kalıbı gösterir: Atomics.add ile atomik toplama ve Atomics.load ile okuma.
main.ts (Tarayıcı tarafı)
Bu örnek, ana iş parçacığının bir SharedArrayBuffer oluşturup onu çoklu iş parçacıklı erişim için bir Worker ile nasıl paylaştığını gösterir.
1// main.ts
2// Create a 4-byte (Int32) shared buffer for one counter
3const sab = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 1);
4const counter = new Int32Array(sab); // view over the buffer
5
6// Create worker and transfer the SharedArrayBuffer
7const worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' });
8worker.postMessage({ sab });
9
10// Increase counter in main thread every 200ms
11setInterval(() => {
12 const newVal = Atomics.add(counter, 0, 1) + 1; // Atomically increment
13 console.log('Main incremented ->', newVal);
14}, 200);
15
16// Listen for messages (optional)
17worker.onmessage = (e) => {
18 console.log('From worker:', e.data);
19};- Bu kodda ana iş parçacığı, değeri atomik olarak artırmak için
Atomics.addkullanır.worker.tstarafında aynıSharedArrayBuffera erişilip üzerinde işlem yapılabilir.
worker.ts (Tarayıcı Worker)
Bu, worker'ın aynı paylaşılan tamponu alıp periyodik olarak azaltma veya üzerinde işlem yaptığı bir örnektir.
1// worker.ts
2self.onmessage = (ev: MessageEvent) => {
3 const { sab } = ev.data as { sab: SharedArrayBuffer };
4 const counter = new Int32Array(sab);
5
6 // Every 350ms, atomically add 2 (demonstration)
7 setInterval(() => {
8 const newVal = Atomics.add(counter, 0, 2) + 2;
9 // Optionally notify main thread (postMessage)
10 self.postMessage(`Worker added 2 -> ${newVal}`);
11 }, 350);
12};- Worker da aynı belleği
Int32Arrayaracılığıyla işler ve güncellemelerAtomicssayesinde veri yarışması olmadan yapılır.
wait/notify kullanarak senkronizasyon
Atomics.wait ve Atomics.notify kullanarak, belirli koşullar karşılanana kadar thread'leri askıya alabilir ve worker thread'leri içinde olay tabanlı senkronizasyon sağlayabilirsiniz. Tarayıcılarda, en güvenli yöntem Atomics.wait fonksiyonunu bir Worker içinde kullanmaktır.
producer.ts (Tarayıcı Üretici Worker)
Üretici, veriyi yazar ve tüketiciyi notify ile bilgilendirir.
1// producer.ts (worker)
2self.onmessage = (ev: MessageEvent) => {
3 const { sab } = ev.data as { sab: SharedArrayBuffer };
4 const state = new Int32Array(sab); // state[0] will be 0=empty,1=filled
5
6 // produce every 500ms
7 setInterval(() => {
8 // produce: set state to 1 (filled)
9 Atomics.store(state, 0, 1);
10 Atomics.notify(state, 0, 1); // wake one waiter
11 self.postMessage('produced');
12 }, 500);
13};consumer.ts (Tarayıcı Tüketici Worker)
Tüketici, Atomics.wait ile bekler ve üreticiden bildirim aldığında işlemeye devam eder.
1// consumer.ts (worker)
2self.onmessage = (ev: MessageEvent) => {
3 const { sab } = ev.data as { sab: SharedArrayBuffer };
4 const state = new Int32Array(sab);
5
6 // consumer loop
7 (async function consumeLoop() {
8 while (true) {
9 // if state is 0 => wait until notified (value changes)
10 while (Atomics.load(state, 0) === 0) {
11 // Blocks this worker until notified or timeout
12 Atomics.wait(state, 0, 0);
13 }
14 // consume (reset to 0)
15 // (processing simulated)
16 // read data from another shared buffer in real scenarios
17 Atomics.store(state, 0, 0);
18 // continue loop
19 self.postMessage('consumed');
20 }
21 })();
22};- Bu desende, üretici
Atomics.notifyile tüketiciyi bilgilendirir ve tüketici deAtomics.waitile verimli biçimde bekler. Tarayıcılarda ana iş parçacığındaAtomics.waitfonksiyonu çağırılamaz. Arayüzün donmasını önlemek için,Atomics.waitancak Worker içinde kullanılabilir.
Node.js ile Pratik Örnek (worker_threads)
Bir Node.js ortamında, SharedArrayBuffer işlevselliğini worker_threads kullanarak yönetebilirsiniz. Aşağıda Node.js için tipli bir TypeScript örneği bulabilirsiniz.
main-node.ts
Ana iş parçacığı tamponu oluşturur ve Worker'a aktarır.
1// main-node.ts
2import { Worker } from 'worker_threads';
3import path from 'path';
4
5// Create SharedArrayBuffer for one 32-bit integer
6const sab = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT);
7const counter = new Int32Array(sab);
8
9// Spawn worker and pass sab via workerData
10const worker = new Worker(path.resolve(__dirname, 'worker-node.js'), {
11 workerData: { sab }
12});
13
14// Log messages from worker
15worker.on('message', (msg) => console.log('Worker:', msg));
16
17// Increment in main thread periodically
18setInterval(() => {
19 const val = Atomics.add(counter, 0, 1) + 1;
20 console.log('Main increment ->', val);
21}, 300);worker-node.ts
Bu örnekte, Worker tarafında worker_threads paketindeki parentPort ve workerData kullanılır.
1// worker-node.ts
2import { parentPort, workerData } from 'worker_threads';
3
4const sab = workerData.sab as SharedArrayBuffer;
5const counter = new Int32Array(sab);
6
7// Periodically add 5
8setInterval(() => {
9 const val = Atomics.add(counter, 0, 5) + 5;
10 parentPort?.postMessage(`Added 5 -> ${val}`);
11}, 700);- Node.js'te, tarayıcıdaki gibi COOP veya COEP kısıtlamaları olmadığından, sadece
worker_threadskullanarak paylaşımlı bellek kolayca yönetilebilir. TypeScript kullanırken, CommonJS mi yoksa ESM ayarlarıyla mı derlediğinize dikkat edin.
TypeScript Tip Notları
SharedArrayBuffer ve Atomics, standart DOM ve kütüphane tip tanımlarında yer alır, bu yüzden doğrudan TypeScript içerisinde kullanılabilirler. Worker'larla mesaj alışverişinde bulunurken arayüz tanımlamak ve tipleri açıkça belirtmek daha güvenlidir.
1// Example: typed message
2type WorkerMessage = { type: 'init'; sab: SharedArrayBuffer } | { type: 'ping' };- Tiplerin açıkça tanımlanması,
postMessageveonmessageişlemlerinin daha güvenli olmasını sağlar ve tip kontrolüne imkan verir.
Pratik Kullanım Senaryoları
SharedArrayBuffer her zaman gerekli değildir, ancak paylaşılan belleğin hız avantajlarının gerektiği durumlarda son derece etkilidir.`. Hangi durumlarda etkili olduğunu anlamak, uygun teknoloji seçimlerine yol açar.
- Yüksek hızlı paylaşımlı tampon gerektiren ve düşük gecikmeli işlem isteyen durumlarda; gerçek zamanlı ses/görüntü işleme veya oyun fiziği gibi alanlarda kullanılabilir.
- Basit veri alışverişi ya da büyük miktarda veri aktarımı için,
Transferable ArrayBufferveyapostMessage,SharedArrayBufferdan daha kolay olabilir.
Kısıtlamalar ve Güvenlik
Tarayıcıda SharedArrayBuffer kullanmak için çapraz kaynak izolasyonu gerekir: COOP'u same-origin-allow-popups ve COEP'i require-corp olarak ayarlayın. Bu gereksinimler karşılanmazsa, SharedArrayBuffer devre dışı bırakılır.
Performans ve Hata Ayıklama İpuçları
Atomik işlemler (Atomics) hızlıdır, ancak sık bekleme ve aşırı senkronizasyon gecikmeyi artırabilir.
Paylaşımlı belleği güvenli ve verimli şekilde kullanmak için aşağıdaki noktaları kontrol edin.
Int32Arraygibi görünümler, uygun bayt hizalaması ile kullanılmalıdır.- Aynı paylaşımlı tamponun hangi dizinlerinin hangi işlemler tarafından kullanıldığını netleştirin ve kodunuzda tutarlı kullanım kuralları oluşturun.
SharedArrayBufferı normal birArrayBufferolarak kullanırsanız, veri yarışmaları meydana gelir.Atomicskullanılmadan, birden fazla iş parçacığının aynı dizine yazması tehlikelidir.
Özet
SharedArrayBuffer ve Atomicsi doğru şekilde kullanarak, TypeScript'te bile güvenli ve hızlı paylaşımlı bellek işlemleri gerçekleştirebilirsiniz. Sayaç veya sinyal gibi basit senkronizasyon kalıplarıyla başlamak daha kolaydır; doğru senkronizasyon ve dizinleri titizlikle yöneterek düşük gecikme gerektiren senaryolarda bile etkili olabilirsiniz.
Yukarıdaki makaleyi, YouTube kanalımızda Visual Studio Code'u kullanarak takip edebilirsiniz. Lütfen YouTube kanalını da kontrol edin.