โฮมเพจ » การเข้ารหัส » รู้เบื้องต้นเกี่ยวกับหน่วยความจำที่ใช้ร่วมกันใน JavaScript

    รู้เบื้องต้นเกี่ยวกับหน่วยความจำที่ใช้ร่วมกันใน 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 สามารถช่วยคุณด้วยความยากลำบากบางอย่าง, โดยการลดลักษณะการอ่าน / การเขียนที่ไม่สามารถคาดเดาได้จากหน่วยความจำที่ใช้ร่วมกัน.