Mutexes จำเป็นใน JavaScript หรือไม่?


104

ฉันได้เห็นลิงค์นี้: การดำเนินการร่วมกันยกเว้นใน JavaScript ในทางกลับกันฉันได้อ่านว่าไม่มีเธรดในจาวาสคริปต์ แต่นั่นหมายความว่าอย่างไร?

เมื่อเหตุการณ์เกิดขึ้นพวกเขาสามารถขัดจังหวะได้ที่ไหนในโค้ด

และถ้าไม่มีเธรดใน JS ฉันจำเป็นต้องใช้ mutexes ใน JS หรือไม่?

โดยเฉพาะอย่างยิ่งฉันสงสัยเกี่ยวกับผลกระทบของการใช้ฟังก์ชันที่เรียกโดยsetTimeout()และXmlHttpRequestของonreadystatechangeตัวแปรที่เข้าถึงได้ทั่วโลก


1
ไม่ไม่มี mutex หรือเครื่องมือควบคุมการทำงานพร้อมกันอื่น ๆ ในจาวาสคริปต์ ดูทำไมไม่มีเครื่องมือควบคุมภาวะพร้อมกันใน JavaScript
Uzair Farooq

คำตอบ:


101

Javascript ถูกกำหนดให้เป็นภาษาreentrantซึ่งหมายความว่าไม่มีเธรดที่เปิดเผยต่อผู้ใช้อาจมีเธรดในการนำไปใช้งาน ฟังก์ชันเช่นsetTimeout()และการเรียกกลับแบบอะซิงโครนัสจำเป็นต้องรอให้สคริปต์เอ็นจินเข้าสู่โหมดสลีปก่อนจึงจะสามารถทำงานได้

นั่นหมายความว่าทุกอย่างที่เกิดขึ้นในเหตุการณ์จะต้องเสร็จสิ้นก่อนที่เหตุการณ์ต่อไปจะได้รับการประมวลผล

ดังที่กล่าวไว้คุณอาจต้องใช้ mutex หากรหัสของคุณทำบางอย่างโดยที่คาดว่าค่าจะไม่เปลี่ยนแปลงระหว่างเวลาที่เหตุการณ์อะซิงโครนัสเริ่มทำงานและเมื่อมีการเรียกกลับ

ตัวอย่างเช่นหากคุณมีโครงสร้างข้อมูลที่คุณคลิกปุ่มเดียวและส่ง XmlHttpRequest ซึ่งเรียกการเรียกกลับการเปลี่ยนแปลงโครงสร้างข้อมูลในลักษณะทำลายล้างและคุณมีปุ่มอื่นที่เปลี่ยนโครงสร้างข้อมูลเดียวกันโดยตรงระหว่างเมื่อเหตุการณ์นั้น เริ่มทำงานและเมื่อดำเนินการโทรกลับผู้ใช้สามารถคลิกและอัปเดตโครงสร้างข้อมูลก่อนการติดต่อกลับซึ่งอาจสูญเสียค่าไป

ในขณะที่คุณสามารถสร้างเงื่อนไขการแข่งขันแบบนั้นได้ แต่มันง่ายมากที่จะป้องกันสิ่งนั้นในโค้ดของคุณเนื่องจากแต่ละฟังก์ชันจะเป็นอะตอม มันจะเป็นงานมากและใช้รูปแบบการเข้ารหัสแปลก ๆ เพื่อสร้างเงื่อนไขการแข่งขันในความเป็นจริง


14
การสร้างเงื่อนไขการแข่งขันนี้ไม่ใช่เรื่องยากเลยตัวอย่างเช่นฉันมีเหตุการณ์ "onkeyup" ในฟิลด์ที่ทริกเกอร์การเรียก ajax ไปยัง DB เพื่อรับค่าบางอย่าง การพิมพ์ข้อมูลอย่างรวดเร็วสามารถนำไปสู่ผลลัพธ์ที่ไม่ตรงตามคำสั่งได้อย่างง่ายดาย
thomasb

19

คำตอบสำหรับคำถามนี้ค่อนข้างล้าสมัยแม้ว่าจะถูกต้องในเวลาที่ได้รับ และยังคงถูกต้องหากดูแอปพลิเคชันจาวาสคริปต์ฝั่งไคลเอ็นต์ที่ไม่ใช้เว็บเวิร์ค

บทความเกี่ยวกับผู้ปฏิบัติงานบนเว็บ: การอ่าน
หลายเธรดในจาวาสคริปต์โดยใช้
โปรแกรมทำงานบนเว็บ Mozilla บน Webworkers

สิ่งนี้แสดงให้เห็นอย่างชัดเจนว่าจาวาสคริปต์ผ่านเว็บเวิร์คมีความสามารถในการทำงานหลายเธรด เกี่ยวกับคำถาม mutexes จำเป็นใน javascript หรือไม่? ฉันไม่แน่ใจในเรื่องนี้ แต่โพสต์ stackoverflow นี้ดูเหมือนจะเกี่ยวข้อง:
การยกเว้นร่วมกันสำหรับ N Asynchronous Threads


3
ระเบิดจากอดีต แต่ฉันพบความจำเป็นในการ mutexes เมื่อหลายแท็บเข้าถึงที่เก็บข้อมูลในเครื่องเดียวกัน
psp

3
WebWorkers ไม่ส่งผลกระทบต่อการเข้าร่วมอีกครั้งเนื่องจากไม่แชร์สถานะตัวแปรและสื่อสารกับเธรดหลักโดยการส่งข้อความเท่านั้นซึ่งจะทำให้เกิดเหตุการณ์
Alnitak

9

ดังที่ @ วิลเลียมชี้ให้เห็นว่า

คุณอาจต้องใช้ mutex หากโค้ดของคุณทำอะไรบางอย่างโดยที่คาดว่าค่าจะไม่เปลี่ยนแปลงระหว่างเวลาที่เหตุการณ์อะซิงโครนัสเริ่มทำงานและเวลาที่เรียกกลับ

สิ่งนี้สามารถสรุปได้เพิ่มเติม - หากโค้ดของคุณทำอะไรบางอย่างที่คาดว่าจะมีการควบคุมเฉพาะทรัพยากรจนกว่าคำขอแบบอะซิงโครนัสจะได้รับการแก้ไขคุณอาจต้องใช้ mutex

ตัวอย่างง่ายๆคือคุณมีปุ่มที่เริ่มการเรียกใช้ ajax เพื่อสร้างเรกคอร์ดที่ส่วนหลัง คุณอาจต้องใช้รหัสเล็กน้อยเพื่อปกป้องคุณจากการกระตุ้นให้ผู้ใช้ที่มีความสุขคลิกออกไปและด้วยเหตุนี้การสร้างระเบียนหลายรายการ มีหลายวิธีในการแก้ไขปัญหานี้ (เช่นปิดการใช้งานปุ่มเปิดใช้งาน ajax สำเร็จ) คุณยังสามารถใช้การล็อคแบบธรรมดา:

var save_lock = false;
$('#save_button').click(function(){
    if(!save_lock){
        //lock
        save_lock=true;
        $.ajax({
            success:function()
                //unlock
                save_lock = false;  
            }
        });
    }
}

ฉันไม่แน่ใจว่านั่นเป็นแนวทางที่ดีที่สุดหรือไม่และฉันสนใจที่จะดูว่าคนอื่นจัดการกับการยกเว้นร่วมกันในจาวาสคริปต์อย่างไร แต่เท่าที่ฉันรู้ว่าเป็นวิธีปิดเสียงที่เรียบง่ายและมีประโยชน์


4
ฉันแทบจะไม่เรียกสิ่งนี้ว่า mutex อย่างน้อยก็ไม่ใช่ในความหมายดั้งเดิมเพราะคุณไม่มีสองเธรดที่ทำงานในบริบทของบล็อกเดียวตลอดเวลา
Ovesh

10
mutex เป็นเพียงอัลกอริทึมที่ช่วย 'หลีกเลี่ยงการใช้ทรัพยากรร่วมกันในเวลาเดียวกัน' แม้ว่ามัลติเธรดจะสร้างความต้องการ mutexes แต่ก็ไม่มีอะไรในคำจำกัดความที่ระบุว่า mutex มีความเฉพาะเจาะจงกับสถานการณ์ที่คุณอธิบาย
alzclarke

1
คุณเข้าใจถูกต้องเกี่ยวกับคำจำกัดความที่เป็นทางการของ mutex แต่นี่ไม่ใช่สิ่งที่ผู้คนคิดเมื่อพูดถึง mutexes ในโลกแห่งความเป็นจริง
Ovesh

สิ่งนี้ไม่ทำงานตามที่คาดไว้ ขออภัยการคลิกซ้ำ ๆ จะยังคงทำให้การโทรของ ajax เริ่มทำงาน ความคิดอื่น ๆ ?
Mohammed Shareef C

1
ค่อนข้างแน่ใจว่าสิ่งนี้ควรถูกรวมไว้whileด้วยsetTimeoutหรือsetIntervalด้วยclearIntervalafter n ล้มเหลวเพื่อให้คุณได้ลองใหม่และตรรกะการหมดเวลา การออกตามสภาพหมายความว่าคุณเพียงแค่ข้ามรหัสที่ถูกล็อก การจัดการภายนอกด้วย mutexes และวัตถุที่แบ่งใช้มีความสำคัญพอ ๆ กับการนำไปใช้งานเอง
MrMesees

6

JavaScript เป็นเธรดเดียว ... แม้ว่า Chrome อาจเป็นสัตว์ร้ายตัวใหม่ (ฉันคิดว่ามันเป็นเธรดเดียว แต่แต่ละแท็บมีเธรด JavaScript ของตัวเอง ... ฉันยังไม่ได้ดูรายละเอียดดังนั้นอย่าอ้างฉัน นั่นเอง).

อย่างไรก็ตามสิ่งหนึ่งที่คุณต้องกังวลคือ JavaScript ของคุณจะจัดการกับคำขอ ajax หลายรายการที่กลับมาไม่ใช่ลำดับเดียวกับที่คุณส่งไป ดังนั้นสิ่งที่คุณต้องกังวลจริงๆคือตรวจสอบให้แน่ใจว่าการโทร ajax ของคุณได้รับการจัดการในลักษณะที่พวกเขาจะไม่เหยียบเท้าของกันและกันหากผลลัพธ์กลับมาในลำดับที่แตกต่างจากที่คุณส่งไป

นี่ก็หมดเวลาเช่นกัน ...

เมื่อ JavaScript เติบโตแบบมัลติเธรดอาจกังวลเกี่ยวกับ mutexes และสิ่งที่คล้ายกัน ...


4

ใช่สามารถใช้ mutexes ใน Javascript เมื่อเข้าถึงทรัพยากรที่ใช้ร่วมกันระหว่างแท็บ / หน้าต่างเช่นlocalStorage localStorage

ตัวอย่างเช่นหากผู้ใช้เปิดแท็บสองแท็บโค้ดง่ายๆดังต่อไปนี้จะไม่ปลอดภัย:

function appendToList(item) {
    var list = localStorage["myKey"];
    if (list) {
        list += "," + item;
    }
    else {
        list = item;
    }
    localStorage["myKey"] = list;
}

ระหว่างเวลาที่รายการ localStorage 'got' และ 'set' แท็บอื่นอาจแก้ไขค่าได้ โดยทั่วไปไม่น่าเป็นไปได้ แต่เป็นไปได้ - คุณต้องตัดสินด้วยตัวเองถึงความเป็นไปได้และความเสี่ยงที่เกี่ยวข้องกับการทะเลาะวิวาทในสถานการณ์เฉพาะ

ดูบทความต่อไปนี้สำหรับรายละเอียดเพิ่มเติม:


2

JavaScript ซึ่งเป็นภาษาสามารถเป็นแบบมัลติเธรดได้ตามที่คุณต้องการ แต่การฝังเบราว์เซอร์ของเอ็นจิ้นจาวาสคริปต์จะเรียกใช้การเรียกกลับเพียงครั้งเดียว (onload, onfocus, <script> และอื่น ๆ ... ) ในแต่ละครั้ง (ต่อแท็บ) ข้อเสนอแนะของวิลเลียมในการใช้ Mutex สำหรับการเปลี่ยนแปลงระหว่างการลงทะเบียนและการรับการโทรกลับไม่ควรนำมาใช้อย่างแท้จริงด้วยเหตุนี้เนื่องจากคุณไม่ต้องการบล็อกการโทรกลับที่แทรกแซงเนื่องจากการโทรกลับที่จะปลดล็อกจะถูกบล็อกหลังการโทรกลับปัจจุบัน ! (ว้าวภาษาอังกฤษแย่มากสำหรับการพูดถึงเธรด) ในกรณีนี้คุณอาจต้องการทำอะไรบางอย่างตามแนวการกระจายเหตุการณ์ปัจจุบันอีกครั้งหากมีการตั้งค่าสถานะไม่ว่าจะตามตัวอักษรหรือชอบ setTimeout ()

หากคุณใช้การฝัง JS ที่แตกต่างกันและดำเนินการหลายเธรดพร้อมกันอาจทำให้มีความเสี่ยงมากขึ้นเล็กน้อย แต่เนื่องจากวิธีที่ JS สามารถใช้การโทรกลับได้อย่างง่ายดายและการล็อกอ็อบเจ็กต์ในการล็อกการเข้าถึงคุณสมบัติอย่างชัดเจนจึงไม่เกือบเท่าที่จำเป็น . อย่างไรก็ตามฉันจะแปลกใจถ้าการฝังที่ออกแบบมาสำหรับรหัสทั่วไป (เช่นการเขียนสคริปต์เกม) ที่ใช้เธรดแบบหลายเธรดไม่ได้ให้การล็อกแบบดั้งเดิมที่ชัดเจนเช่นกัน

ขออภัยสำหรับผนังข้อความ!


0

เหตุการณ์ถูกส่งสัญญาณ แต่การเรียกใช้ JavaScript ยังคงเป็นเธรดเดียว

ความเข้าใจของฉันคือเมื่อเหตุการณ์ถูกส่งสัญญาณเครื่องยนต์จะหยุดสิ่งที่กำลังดำเนินการในขณะนี้เพื่อเรียกใช้ตัวจัดการเหตุการณ์ หลังจากตัวจัดการเสร็จสิ้นการเรียกใช้สคริปต์จะกลับมาทำงานอีกครั้ง หากตัวจัดการเหตุการณ์เปลี่ยนตัวแปรที่ใช้ร่วมกันบางตัวโค้ดที่กลับมาทำงานใหม่จะเห็นการเปลี่ยนแปลงเหล่านี้ปรากฏ "ออกจากสีน้ำเงิน"

หากคุณต้องการ "ปกป้อง" ข้อมูลที่แชร์การตั้งค่าสถานะบูลีนอย่างง่ายก็น่าจะเพียงพอแล้ว

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.