مقدمة في الذاكرة المشتركة في JavaScript
ذكريات مشتركه هي ميزة متقدمة لجافا سكريبت ، والتي يمكن أن مؤشرات الترابط (أجزاء تنفذ في وقت واحد من عملية) الاستفادة. مشاركة الذاكرة تعني عدم وجود مشكلة في تمرير البيانات المحدثة بين المواضيع ويمكن لجميع مؤشرات الترابط الوصول إلى نفس البيانات وتحديثها في الذاكرة المشتركة.
لا هذا الصوت جميل؟ حسنا ، تقريبا. في هذا المنشور ، سنرى كيفية استخدام الذاكرة المشتركة في جافا سكريبت وكيف تقرر ما إذا كان هذا هو ما تريد فعله حقًا.
مزايا وعيوب الذاكرة المشتركة
نحن نستخدم عمال الويب إلى إنشاء المواضيع في جافا سكريبت. تسمح واجهة برمجة تطبيقات Web Workers API لنا بإنشاء مؤشرات ترابط عامل يمكن استخدامها تنفيذ التعليمات البرمجية في الخلفية بحيث يكون مؤشر الترابط الرئيسي مجانيًا لمواصلة تنفيذه ، وربما معالجة أحداث واجهة المستخدم ، مع ضمان عدم تجميد واجهة المستخدم.
المواضيع عامل تشغيل بالتزامن مع الموضوع الرئيسي وبعضها البعض. مثل هذا التنفيذ المتزامن لأجزاء مختلفة من المهمة هو توفير الوقت. تنتهي بشكل أسرع ، ولكن لديها أيضًا مجموعة من المشكلات الخاصة بها.
التأكد من أن كل موضوع يحصل على الموارد اللازمة ويتواصل مع بعضهم البعض في الوقت المناسب هي مهمة في حد ذاتها ، حيث يمكن أن ينتج عن حادث ما نتيجة مدهشة. أو إذا مؤشر ترابط واحد هو تغيير البيانات وآخر يقرأها في نفس الوقت, ما رأيك في الخيط الآخر سوف يرى؟ المحدثة أو البيانات القديمة?
ومع ذلك ، فإن عمال الويب ليسوا بهذه السهولة. أثناء اتصالهم عبر استخدام الرسائل ، تكون البيانات التي يرسلونها بعضهم البعض ليست أصلية ولكن نسخة, وهذا يعني أنهم لا شارك نفس البيانات. هم تمرير نسخ من البيانات إلى بعضها البعض عند الاحتياج.
ولكن المشاركة مهمة ، وقد تحتاج سلاسل مؤشرات متعددة أيضًا إلى النظر إلى نفس البيانات في نفس الوقت وتغييرها. وبالتالي, حظر المشاركة هو لا لا. هذا هو المكان الذي SharedArrayBuffer
كائن يأتي في الصورة. سوف تسمح لنا مشاركة البيانات الثنائية بين عدة مؤشرات ترابط.
ال SharedArrayBuffer
موضوع
بدلا من تمرير نسخ البيانات بين المواضيع ، ونحن تمرير نسخ من SharedArrayBuffer
موضوع. ا SharedArrayBuffer
موضوع يشير إلى الذاكرة حيث يتم حفظ البيانات.
لذلك ، حتى عندما نسخ SharedArrayBuffer
يتم تمريرها بين المواضيع ، فإنها كل شيء سوف لا يزال يشير إلى نفس الذاكرة حيث يتم حفظ البيانات الأصلية. المواضيع ، وبالتالي ، يمكن عرض وتحديث البيانات في تلك الذاكرة نفسها.
عمال الويب بدون ذكريات مشتركه
لنرى كيف يعمل عامل الويب دون استخدام الذاكرة المشتركة ، نحن إنشاء موضوع عامل و تمرير بعض البيانات إليها.
ال index.html و
ملف يحمل النصي الرئيسي داخل العلامة ، كما ترون أدناه:
const w = new Worker ('worker.js') ؛ فار ن = 9 ؛ w.postMessage (ن)؛
ال worker.js
يحمل الملف النصي العامل:
onmessage = (e) => console.group ('[worker]') ؛ console.log ('البيانات المستلمة من سلسلة الرسائل الرئيسية:٪ i' ، e.data) ؛ console.groupEnd ()؛
باستخدام الرمز أعلاه ، نحصل على ما يلي الإخراج في وحدة التحكم:
[عامل] البيانات الواردة من الموضوع الرئيسي: 9
يمكنك قراءة مشاركتي الآنفة الذكر على العاملين على شبكة الإنترنت للحصول على شرح كامل للشفرة للقصاصات أعلاه.
الآن ، ضع في اعتبارك أن البيانات موجودة أرسلت جيئة وذهابا بين المواضيع باستخدام postMessage ()
طريقة. البيانات هي وردت على الجانب الآخر من قبل رسالة
معالج الحدث, كقيمة الحدث البيانات
خاصية.
الآن ، إذا نحن تغيير البيانات سوف تظهر محدثة في الطرف المتلقي؟ لنرى:
const w = new Worker ('worker.js') ؛ فار ن = 9 ؛ w.postMessage (ن)؛ ن = 1 ؛
كما هو متوقع ، فإن البيانات لديها ليس تم تحديثه:
[عامل] البيانات الواردة من الموضوع الرئيسي: 9
لماذا سيكون ، على أي حال؟ انها مجرد استنساخ أرسلت للعامل من السيناريو الرئيسي.
عمال الويب مع ذكريات مشتركه
الآن ، نحن سوف استخدم ال SharedArrayBuffer
موضوع في نفس المثال. يمكننا إنشاء جديد SharedArrayBuffer
المثال من قبل باستخدام الجديد
الكلمة. يأخذ المنشئ معلمة واحدة ؛ ا قيمة الطول بالبايت, تحديد حجم المخزن المؤقت.
const w = new Worker ('worker.js') ؛ buff = جديد SharedArrayBuffer (1) ؛ var arr = Int8Array (برتقالي) جديد ؛ / * إعداد البيانات * / arr [0] = 9 ؛ / * إرسال المخزن المؤقت (نسخة) إلى العامل * / w.postMessage (برتقالي) ؛
لاحظ أن SharedArrayBuffer
موضوع يمثل فقط مساحة الذاكرة المشتركة. إلى رؤية وتغيير البيانات الثنائية, نحن بحاجة إلى استخدام بنية بيانات مناسبة (أ TypedArray
أو عرض البيانات
موضوع).
في ال index.html و
الملف أعلاه ، جديد SharedArrayBuffer
تم إنشاؤه ، مع طول بايت واحد فقط. ثم جديد Int8Array
, وهو نوع واحد من TypedArray
الكائنات ، ويستخدم ل اضبط البيانات على “9” في مساحة البايت المقدمة.
onmessage = (e) => var arr = new Int8Array (e.data)؛ console.group ( '[عامل]')؛ console.log ('البيانات المستلمة من سلسلة الرسائل الرئيسية:٪ i' ، arr [0]) ؛ console.groupEnd ()؛
Int8Array
يستخدم أيضا في العامل ، ل عرض البيانات في المخزن المؤقت.
ال تظهر القيمة المتوقعة في وحدة التحكم من الخيط العامل ، وهذا بالضبط ما أردنا:
[عامل] البيانات الواردة من الموضوع الرئيسي: 9
دعنا الآن تحديث البيانات في الموضوع الرئيسي لمعرفة ما إذا كان التغيير ينعكس في العامل.
const w = new Worker ('worker.js') ، buff = new SharedArrayBuffer (1)؛ var arr = Int8Array (برتقالي) جديد ؛ / * إعداد البيانات * / arr [0] = 9 ؛ / * إرسال المخزن المؤقت (نسخة) إلى العامل * / w.postMessage (برتقالي) ؛ / * تغيير البيانات * / arr [0] = 1 ؛
وكما ترى أدناه ، التحديث هل يعكس داخل العامل!
[عامل] البيانات الواردة من الموضوع الرئيسي: 1
ولكن ، رمز أيضا يحتاج إلى العمل في الاتجاه المعاكس: عندما تتغير القيمة في العامل في البداية ، يحتاج أيضا إلى تحديث عند طباعته من الخيط الرئيسي.
في هذه الحالة ، يبدو الرمز الخاص بنا كما يلي:
onmessage = (e) => var arr = new Int8Array (e.data)؛ console.group ( '[عامل]')؛ console.log ('البيانات المستلمة من سلسلة الرسائل الرئيسية:٪ i' ، arr [0]) ؛ console.groupEnd ()؛ / * تغيير البيانات * / arr [0] = 7 ؛ / * النشر إلى سلسلة الرسائل الرئيسية * / postMessage (")؛
ال يتم تغيير البيانات في العامل و تم نشر رسالة فارغة في الموضوع الرئيسي مما يشير إلى أن البيانات الموجودة في المخزن المؤقت قد تم تغييرها وهي جاهزة لإخراج مؤشر الترابط الرئيسي.
const w = new Worker ('worker.js') ، buff = new SharedArrayBuffer (1)؛ var arr = Int8Array (برتقالي) جديد ؛ / * إعداد البيانات * / arr [0] = 9 ؛ / * إرسال المخزن المؤقت (نسخة) إلى العامل * / w.postMessage (برتقالي) ؛ / * تغيير البيانات * / arr [0] = 1 ؛ / * طباعة البيانات بعد تغيير العامل * / w.onmessage = (e) => console.group ('[main]')؛ console.log ('البيانات المحدّثة المستلمة من خيط عامل:٪ i' ، arr [0]) ؛ console.groupEnd ()؛
وهذا يعمل أيضا! البيانات الموجودة في المخزن المؤقت هي نفس البيانات الموجودة داخل العامل.
[عامل] البيانات الواردة من الموضوع الرئيسي: 1 [رئيسي] البيانات المحدثة الواردة من مؤشر ترابط العامل: 7
القيمة يبدو محدثة في كلتا الحالتين. يتم عرض مؤشرات الترابط الرئيسية والعامل وتغيير نفس البيانات.
الكلمات الأخيرة
كما ذكرت سابقًا ، باستخدام الذاكرة المشتركة في JavaScript ليس من دون سلبيات. الأمر متروك للمطورين لضمان أن تسلسل التنفيذ يحدث كما هو متوقع وليس هناك خيطان يتسابقان للحصول على نفس البيانات لأن لا أحد يعرف من سيأخذ الكأس.
إذا كنت مهتمًا بالذاكرة المشتركة أكثر ، فقم بإلقاء نظرة على وثائق أتوميكس
موضوع. ال كائن Atomics يمكن أن تساعدك في بعض المصاعب, عن طريق تقليل الطبيعة غير المتوقعة للقراءة / الكتابة من الذاكرة المشتركة.