JS’s Atomics یک مقدمه، چند رشته ای و حافظه را ایراد می کند!

جاوا اسکریپت مورد علاقه ما تک رشته ای است و به این ترتیب، تنها می تواند یک چیز را در یک زمان اجرا کند. این را ذخیره کنید، این مهم است!
بنابراین اگر یک کار طولانی مدت، رشته اصلی مرورگر را مسدود کند، مرورگر برای رندر کردن مشکل خواهد داشت.
به عنوان مثال، اگر بخواهیم حلقهای را در یک ساختار داده بزرگ انجام دهیم،
یا یک حلقه ساده بسیار بزرگ ایجاد کنید.
این می تواند باعث یخ زدن رندر شود. در حالی که حلقه تمام نشد، یا زمانی که الگوریتم در حال عبور از ساختار کلان داده بود، کاری نمی توانید انجام دهید، فقط تماشا کنید و منتظر بمانید.
این یک مشکل تک رشته ای است.
شما در هر زمان فقط می توانید یک کار را انجام دهید و اگر خیلی طول بکشد، هیچ کار دیگری نمی توانید انجام دهید!
در این متن از تماس ها و وعده ها صحبت نمی کنیم.
یکی از راه حل های این مشکل استفاده از Web Workers است.
Web Workers مکانیسم هایی هستند که به یک عملیات از یک اسکریپت داده شده اجازه می دهند در رشته ای غیر از رشته اصلی برنامه وب اجرا شود. امکان پردازش محاسبات پرزحمت بدون مسدود کردن رشته اصلی (که معمولاً با رابط مرتبط است).
منبع > mdn.
می دانیم که js تک رشته ای است.
با گذشت زمان، برنامه های کاربردی در مرورگر بیشتر و بیشتر خواستار شدند.
بنابراین آنها تصمیم گرفتند که کارگران وب را برای کمک به ما بیاورند!
حالا آن حلقه غول پیکر می تواند به یک موضوع دیگر برود و صفحه اصلی ما را زیبا و سبک کند بدون اینکه کسی مانع شود!
Web Workers امکان اجرای موازی در زمینه مرورگر را می دهد.
با این حال، مانند همه چیز در فن آوری، وب کارگران نقاط ضعف خود را دارند. برای مثال، هزینه ای برای انتقال داده به و از موضوع Worker وجود دارد. هر انتقال از طریق postMessage انجام می شود.
مرورگر از الگوریتم کلون ساخت یافته استفاده می کند
برای کپی کردن یک شی، یعنی کپی کردن همان داده در حافظه. این هزینه، بسته به شرایط، می تواند بیشتر از سود تخلیه به نخ Worker باشد.
چه می شود اگر بتوانیم از کپی کردن داده ها خودداری کنیم؟
یکی از راه های حل این مشکل استفاده از آن است SharedArrayBuffer.
برای توسعه دهندگان جاوا اسکریپت، این ساختار به ما اجازه می دهد تا تکه هایی از حافظه مشترک ایجاد کنیم. به جای کپی کردن داده ها از رشته اصلی به Worker و بالعکس، می توانیم همان حافظه مشترک را از هر دو طرف به روز کنیم.
//
const length = 10;
// Criando o tamanho do nosso buffer
const size = Int32Array.BYTES_PER_ELEMENT * length;
// Criando o buffer com 10 inteiros
const sharedBuffer = new SharedArrayBuffer(size);
const sharedArray = new Int32Array(sharedBuffer);
Int32Array چیست:
sharedarraybuffer چیست:
اکنون یک حافظه داریم که می توان آن را به اشتراک گذاشت. یعنی موضوع اصلی و کارمندان وب می توانند با هم به همان مکان دسترسی داشته باشند!
این واقعا خوب است، حافظه را ذخیره می کند!
اما مثل همه چیز در تکنولوژی، معایبی هم دارد!
موارد زیر را تصور کنید: ما 3 یا بیشتر Web Worker داریم که علاوه بر رشته اصلی به یک مکان حافظه دسترسی دارند. این اشتباه خواهد شد.
بسیار اشتباه. ممکن است شرایط مسابقه ای داشته باشیم. همه برای یک مکان رقابت می کنند یا مشکل به روز رسانی یک مکان دو بار با اطلاعات یکسان دارند.
به عبارت دیگر، 2 کارگر می توانند یک کار را همزمان انجام دهند و این اتلاف است.
شرط مسابقه چیست:
بنابراین آنها شی Atomics را ایجاد کردند.
عملیات اتمی تضمین می کند که ما روشی استاندارد برای خواندن و نوشتن داده ها به ترتیب قابل پیش بینی داریم.
Atomics دسترسی همه افراد به حافظه را مدیریت می کند، بنابراین از شرایط مسابقه، هدر رفتن کار و غیره جلوگیری می کند.
اتمی چیست؟
// main.js
const worker = new Worker('worker.js');
const length = 10;
const size = Int32Array.BYTES_PER_ELEMENT * length;
const sharedBuffer = new SharedArrayBuffer(size);
const sharedArray = new Int32Array(sharedBuffer);
for (let i = 0; i < 10; i++) {
Atomics.store(sharedArray, i, 0);
}
worker.postMessage(sharedBuffer);
دسترسی به داده ها در کارگر
// worker.js
self.addEventListener('message', (event) => {
const sharedArray = new Int32Array(event.data);
for (let i = 0; i < 10; i++) {
const arrayValue = Atomics.load(sharedArray, i);
console.log(`The item at array index ${i} is ${arrayValue}`);
}
}, false);
اگر بخواهیم ماتریس کارگر را به روز کنیم چه می شود؟ ما دو گزینه برای این به روز رسانی ها با استفاده از Atomics داریم. می توانیم از store که قبلاً دیدیم استفاده کنیم یا می توانیم از Exchange استفاده کنیم. تفاوت اینجاست که store مقدار ذخیره شده را برمی گرداند و Exchange مقدار جایگزین شده را برمی گرداند. بیایید ببینیم این در عمل چگونه کار می کند:
// worker.js
self.addEventListener('message', (event) => {
const sharedArray = new Int32Array(event.data);
for (let i = 0; i < 10; i++) {
if (i%2 === 0) {
const storedValue = Atomics.store(sharedArray, i, 1);
console.log(`The item at array index ${i} is now ${storedValue}`);
} else {
const exchangedValue = Atomics.exchange(sharedArray, i, 2);
console.log(`The item at array index ${i} was ${exchangedValue}, now 2`);
}
}
}, false);
اکنون میتوانیم آرایه نخ اصلی و کارگر را بخوانیم و بهروزرسانی کنیم. Atomics چند روش دیگر دارد که میتوانیم از آنها برای مدیریت آرایههای مشترک جدیدمان استفاده کنیم. دو تا از مفیدترین روش ها صبر و بیدار شدن هستند. Waitnos به شما این امکان را می دهد که منتظر تغییر در شاخص آرایه باشید و سپس عملیات را ادامه دهید. در عمل، این ممکن است در سمت کارگر چیزی شبیه به این باشد:
self.addEventListener('message', (event) => {
const sharedArray = new Int32Array(event.data);
const arrayIndex = 0;
const expectedStoredValue = 50;
// An optional 4th argument can be passed which is a timeout
Atomics.wait(sharedArray, arrayIndex, expectedStoredValue);
// Log the new value
console.log(Atomics.load(sharedArray, arrayIndex));
}, false);
در اینجا ما انتظار تغییر در arrayIndex0 را داریم که در آن مقدار ذخیره شده مورد انتظار 50 است. بنابراین می توانیم به آن بگوییم که وقتی مقدار ایندکس را تغییر می دهیم از رشته اصلی بیدار شود:
const newArrayValue = 100;
Atomics.store(sharedArray, 0, newArrayValue);
// The index that is being waited on
const arrayIndex = 0;
// The first agent waiting on the value
const queuePos = 1;
Atomics.wake(sharedArray, arrayIndex, queuePos);
توابع دیگری برای راحتی ارائه شده است، مانند add و sub که به ترتیب از شاخص آرایه اضافه یا کم می کنند. اگر به عملیات بیتی علاقه دارید، برخی از آنها از جمله یا، و و xor ارائه شده است.
میتوانیم ببینیم که اتمیها میتوانند از شرایط مسابقه اجتناب کنند و با استفاده از روشهای Atomics، بهروزرسانیهای قابل پیشبینی را برای یک آرایه ایجاد کنند.
برای استفاده از رشته ها، باید آنها را به یک نمایش عددی تبدیل کنیم، به عنوان مثال، یک استاندارد شناخته شده برای رمزگذاری به عنوان UTF-16.
function sharedArrayBufferToUtf16String(buf) {
const array = new Uint16Array(buf);
return String.fromCharCode.apply(null, array);
}
function utf16StringToSharedArrayBuffer(str) {
// 2 bytes for each char
const bytes = str.length *2;
const buffer = new SharedArrayBuffer(bytes);
const arrayBuffer = new Uint16Array(buffer);
for (let i = 0, strLen = str.length; i < strLen; i++) {
arrayBuffer[i] = str.charCodeAt(i);
}
return { array: arrayBuffer, buffer: buffer };
}
const exampleString = "Hello world, this is an example string!";
const sharedArrayBuffer = utf16StringToSharedArrayBuffer(exampleString).buffer;
const backToString = sharedArrayBufferToUtf16String(sharedArrayBuffer);
همه کدها از این متن گرفته شده اند:
من یک مقدمه کوچک بر شی Atomics کردم
به یاد داشته باشید که همه اینها *روی Node هم کار میکنه! *
اگر می خواهید بیشتر بدانید فقط منابع را بخوانید:
https://www.sitepen.com/blog/the-return-of-sharedarraybuffers-and-atomics
https://dev.to/feezyhendrix/worker-threads-in-node-js-2ikh
https://exploringjs.com/es2016-es2017/ch_shared-array-buffer.html
https://blogtitle.github.io/using-javascript-sharedarraybuffers-and-atomics/
https://www.tutorialspoint.com/what-is-the-use-of-atomics-in-javascript
https://webreflection.medium.com/about-sharedarraybuffer-atomics-87f97ddfc098
https://www.geeksforgeeks.org/atomics-in-javascript/
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics