รู้เบื้องต้นเกี่ยวกับหน่วยความจำที่ใช้ร่วมกันใน JavaScript
แชร์หน่วยความจำ เป็นคุณลักษณะขั้นสูงของ JavaScript ที่เธรด (ส่วนที่ดำเนินการพร้อมกันของกระบวนการ) สามารถใช้ประโยชน์ได้ การแชร์หน่วยความจำหมายถึง ไม่มีปัญหาในการส่งข้อมูลที่อัพเดตระหว่างเธรด และเธรดทั้งหมดสามารถเข้าถึงและอัปเดตข้อมูลเดียวกันในหน่วยความจำที่แชร์.
เสียงนั่นไม่น่ารักเหรอ? เกือบแล้ว ในโพสต์นี้เราจะเห็น วิธีใช้หน่วยความจำที่ใช้ร่วมกันใน JavaScript และวิธีการตัดสินใจว่านี่คือสิ่งที่คุณต้องการทำ.
ข้อดี & ข้อเสียของหน่วยความจำที่แชร์
เราใช้ เว็บแรงงาน ไปยัง สร้างหัวข้อใน JavaScript. Web Workers API ช่วยให้เราสามารถสร้างเธรดผู้ปฏิบัติงานที่สามารถใช้ รันรหัสในพื้นหลัง เพื่อให้เธรดหลักมีอิสระในการดำเนินการต่ออาจเป็นไปได้ที่จะประมวลผลกิจกรรม UI เพื่อให้แน่ใจว่าไม่มี UI ค้าง.
เธรดผู้ปฏิบัติงาน รันพร้อมกันกับเธรดหลักและซึ่งกันและกัน. การเรียกใช้ส่วนต่าง ๆ ของงานพร้อมกันนั้นช่วยประหยัดเวลา คุณเสร็จเร็วขึ้น แต่ก็มีปัญหาเช่นกัน.
ตรวจสอบให้แน่ใจว่าแต่ละหัวข้อ ได้รับทรัพยากรที่จำเป็นและสื่อสารซึ่งกันและกันในเวลาที่เหมาะสม เป็นภารกิจในตัวเองที่อุบัติเหตุสามารถส่งผลให้เกิดผลลัพธ์ที่น่าแปลกใจ หรือถ้า เธรดหนึ่งกำลังเปลี่ยนข้อมูลและอีกเธรดหนึ่งกำลังอ่าน ในเวลาเดียวกัน, คุณคิดว่าหัวข้ออื่นจะเห็นอย่างไร อัพเดทหรือข้อมูลเก่า?
อย่างไรก็ตามเว็บเวิร์คไม่ใช่เรื่องง่ายที่จะพลาด ในระหว่างการสื่อสารผ่านการใช้ข้อความข้อมูลที่พวกเขาส่งกันคือ ไม่ใช่ต้นฉบับ แต่เป็นสำเนา, หมายความว่าพวกเขาทำไม่ได้ หุ้น ข้อมูลเดียวกัน พวกเขา ส่งสำเนาข้อมูลให้กัน เมื่อจำเป็น.
แต่การแบ่งปันคือการดูแลและหลายเธรดอาจต้องดูข้อมูลเดียวกันในเวลาเดียวกันและเปลี่ยน ดังนั้น, การห้ามแบ่งปันเป็นเรื่องใหญ่. นี่คือที่ SharedArrayBuffer
วัตถุเข้ามาในภาพ มันจะให้เรา แบ่งปันข้อมูลไบนารีระหว่างหลายเธรด.
SharedArrayBuffer
วัตถุ
แทนที่จะส่งสำเนาข้อมูลระหว่างเธรดเรา ส่งสำเนาของ SharedArrayBuffer
วัตถุ. SharedArrayBuffer
วัตถุ ชี้ไปยังหน่วยความจำที่บันทึกข้อมูล.
ดังนั้นแม้เมื่อสำเนาของ SharedArrayBuffer
ถูกส่งระหว่างเธรด ทั้งหมดจะยังคงชี้ไปที่หน่วยความจำเดียวกัน ตำแหน่งที่บันทึกข้อมูลต้นฉบับ กระทู้จึงสามารถ ดูและอัปเดตข้อมูลในหน่วยความจำเดียวกันนั้น.
เว็บแรงงาน ไม่มี หน่วยความจำที่แชร์
ในการดูว่าเว็บเวิร์คทำงานอย่างไรโดยไม่ใช้หน่วยความจำที่ใช้ร่วมกันเรา สร้างเธรดผู้ปฏิบัติงาน และ ส่งผ่านข้อมูลไปยังมัน.
index.html
ไฟล์เก็บ สคริปต์หลัก ภายใน แท็กดังที่คุณเห็นด้านล่าง:
const w = new Worker ('worker.js'); var n = 9; w.postMessage (n);
worker.js
ไฟล์พกพา สคริปต์ของผู้ปฏิบัติงาน:
onmessage = (e) => console.group ('[คนงาน]'); console.log ('ข้อมูลที่ได้รับจากเธรดหลัก:% i', e.data); console.groupEnd ();
ใช้รหัสด้านบนเราได้รับดังต่อไปนี้ เอาต์พุตในคอนโซล:
[ผู้ปฏิบัติงาน] ข้อมูลที่ได้รับจากเธรดหลัก: 9
คุณสามารถอ่านโพสต์ของฉันบนเว็บเวิร์คสำหรับคำอธิบายโค้ดแบบเต็มของตัวอย่างด้านบน.
สำหรับตอนนี้โปรดทราบว่าข้อมูลคือ ส่งไปมาระหว่างเธรด ใช้ postMessage ()
วิธี. ข้อมูลนั้น ได้รับในอีกด้านหนึ่งโดย ข่าวสาร
จัดการเหตุการณ์, เป็นค่าของเหตุการณ์ ข้อมูล
คุณสมบัติ.
ตอนนี้ถ้าเรา เปลี่ยนข้อมูล จะมีการปรับปรุงเมื่อสิ้นสุดการรับหรือไม่ มาดูกัน:
const w = new Worker ('worker.js'); var n = 9; w.postMessage (n); n = 1;
อย่างที่คาดไว้ ข้อมูลมี ไม่ ได้รับการปรับปรุง:
[ผู้ปฏิบัติงาน] ข้อมูลที่ได้รับจากเธรดหลัก: 9
ทำไมถึงเป็นเช่นนั้น มัน เพียงโคลนนิ่งที่ส่งถึงผู้ทำงานจากสคริปต์หลัก.
เว็บแรงงาน กับ หน่วยความจำที่แชร์
ตอนนี้เราจะ ใช้ SharedArrayBuffer
วัตถุ ในตัวอย่างเดียวกัน เราสามารถสร้างใหม่ SharedArrayBuffer
ตัวอย่างโดย ใช้ ใหม่
คำหลัก. ตัวสร้างใช้เวลาหนึ่งพารามิเตอร์ ค่าความยาวเป็นไบต์, การระบุขนาดของบัฟเฟอร์.
const w = new Worker ('worker.js'); buff = new SharedArrayBuffer (1); var arr = Int8Array ใหม่ (buff); / * การตั้งค่าข้อมูล * / arr [0] = 9; / * ส่งบัฟเฟอร์ (คัดลอก) ไปยังผู้ปฏิบัติงาน * / w.postMessage (buff);
โปรดสังเกตว่า SharedArrayBuffer
วัตถุ แสดงถึงพื้นที่หน่วยความจำที่ใช้ร่วมกันเท่านั้น. ไปยัง ดูและเปลี่ยนข้อมูลไบนารี, เราจำเป็นต้องใช้โครงสร้างข้อมูลที่เหมาะสม (ก TypedArray
หรือ DataView
วัตถุ).
ใน 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 ใหม่ (buff); / * การตั้งค่าข้อมูล * / arr [0] = 9; / * ส่งบัฟเฟอร์ (คัดลอก) ไปยังผู้ปฏิบัติงาน * / w.postMessage (buff); / * การเปลี่ยนข้อมูล * / 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 ใหม่ (buff); / * การตั้งค่าข้อมูล * / arr [0] = 9; / * ส่งบัฟเฟอร์ (คัดลอก) ไปยังผู้ปฏิบัติงาน * / w.postMessage (buff); / * การเปลี่ยนข้อมูล * / arr [0] = 1; / * การพิมพ์ข้อมูลหลังจากผู้ปฏิบัติงานเปลี่ยน * / w.onmessage = (e) => console.group ('[main]'); console.log ('อัปเดตข้อมูลที่ได้รับจากเธรดผู้ปฏิบัติงาน:% i', arr [0]); console.groupEnd ();
และใช้งานได้เช่นกัน! ข้อมูลในบัฟเฟอร์นั้นเหมือนกับข้อมูลภายในพนักงาน.
[ผู้ปฏิบัติงาน] ข้อมูลที่ได้รับจากเธรดหลัก: 1 [หลัก] อัปเดตข้อมูลที่ได้รับจากเธรดผู้ปฏิบัติงาน: 7
มูลค่า ปรากฏขึ้นในทั้งสองกรณี; ทั้งเธรดหลักและเธรดผู้ปฏิบัติงานกำลังดูและเปลี่ยนแปลงข้อมูลเดียวกัน.
คำพูดสุดท้าย
อย่างที่ฉันได้กล่าวไปก่อนหน้านี้การใช้หน่วยความจำที่แชร์ใน JavaScript ไม่ได้ไม่มีข้อเสีย. มันขึ้นอยู่กับนักพัฒนาเพื่อให้แน่ใจว่า ลำดับของการดำเนินการเกิดขึ้นตามที่คาดการณ์ไว้ และไม่มีสองกระทู้ที่แข่งกันเพื่อให้ได้ข้อมูลเดียวกันเพราะไม่มีใครรู้ว่าใครจะได้ถ้วยรางวัล.
หากคุณมีความสนใจในหน่วยความจำที่ใช้ร่วมกันมากขึ้นดูที่เอกสารของ อะตอม
วัตถุ. วัตถุ Atomics สามารถช่วยคุณด้วยความยากลำบากบางอย่าง, โดยการลดลักษณะการอ่าน / การเขียนที่ไม่สามารถคาดเดาได้จากหน่วยความจำที่ใช้ร่วมกัน.