Mutexes สามารถเร็วกว่าช่องทางในกรณีการใช้งานที่เฉพาะเจาะจงเป็นหลักเนื่องจากลักษณะที่มีน้ำหนักเบาและวิธีที่พวกเขาจัดการการโต้แย้งและการซิงโครไนซ์ นี่คือคำอธิบายโดยละเอียดพร้อมบริบทที่ Mutexes มีประสิทธิภาพสูงกว่าช่อง:
ความแตกต่างพื้นฐานที่มีผลต่อประสิทธิภาพ
Mutexes ให้การยกเว้นซึ่งกันและกันโดยอนุญาตให้มีเพียงหนึ่งเธรดหรือ goroutine เพื่อเข้าถึงส่วนที่สำคัญในแต่ละครั้ง ภายในการดำเนินการ Mutex มักจะเกี่ยวข้องกับคำแนะนำอะตอมและอาจเกี่ยวข้องกับการปิดกั้นระดับเคอร์เนลเฉพาะเมื่อมีการโต้แย้ง ด้วยเหตุนี้การดำเนินการล็อค/ปลดล็อค Mutex ที่ไม่ได้รับการแก้ไขจึงมักจะมีค่าใช้จ่ายเพียงไม่กี่นาโนวินาที
ในทางตรงกันข้ามช่องเป็นนามธรรมระดับสูงที่ออกแบบมาสำหรับการสื่อสารระหว่าง goroutines หรือเธรด การส่งหรือรับในช่องจะเกี่ยวข้องกับการจัดการคิวการจัดสรรหน่วยความจำที่เป็นไปได้การกำหนดเวลา goroutines และตื่นขึ้นมาหากนอนหลับ ค่าใช้จ่ายนี้หมายถึงแม้แต่การกลายพันธุ์ของรัฐที่เรียบง่ายได้รับการปกป้องจากช่องทางที่มีค่าใช้จ่ายมากขึ้นเมื่อเทียบกับ mutex เนื่องจากการสลับบริบทและงานประสานงาน
ความแตกต่างพื้นฐานเหล่านี้บ่งชี้ว่าทำไมสำหรับการป้องกันตัวแปรที่ใช้ร่วมกันอย่างง่ายหรือส่วนที่สำคัญ mutexes มักจะเร็วขึ้น
ใช้กรณีที่ mutexes เร็วขึ้น
การคุ้มครองสถานะที่ใช้ร่วมกันอย่างง่าย
เมื่อโปรแกรมจำเป็นต้องปกป้องตัวแปรที่ใช้ร่วมกันเช่นเคาน์เตอร์แผนที่หรือธงอย่างง่าย mutexes จะเร็วกว่ามากเนื่องจากส่วนสำคัญเกี่ยวข้องกับค่าใช้จ่ายในการซิงโครไนซ์น้อยที่สุด ตัวอย่าง ได้แก่ :
- การนับการร้องขอในเว็บเซิร์ฟเวอร์: การดำเนินการเพิ่มการร้องขอแต่ละครั้งสามารถได้รับการปกป้องโดย mutex โดยไม่ต้องใช้ค่าใช้จ่ายในการส่งข้อความผ่านช่องทางซึ่งจะเพิ่มความล่าช้าในการจัดคิวและการกำหนดเวลา Mutexes อนุญาตให้ตรงไปตรงมาการเข้าถึงโดยตรงและได้รับการแสดงเพื่อปรับปรุงปริมาณงานตามลำดับขนาดหรือมากกว่า
- การเข้าถึงแคชหรือแผนที่ที่ใช้ร่วมกัน: การปกป้องโครงสร้างข้อมูลด้วย Mutexes ข้อเสนอการอ่านแบบอินไลน์และเขียนด้วยค่าใช้จ่ายน้อยที่สุด การใช้ช่องเป็นตัวกลางที่นี่จะแนะนำเวลาแฝงพิเศษเนื่องจากการเข้าถึงทุกครั้งจะกลายเป็นการเดินทางไปกลับตามคำขอ
การทดสอบมาตรฐานแสดงให้เห็นว่าเคาน์เตอร์ที่ใช้ Mutex สามารถเร็วกว่าเคาน์เตอร์ที่ใช้ช่องสัญญาณประมาณ 75 เท่าเนื่องจากค่าใช้จ่ายที่ลดลงในการซิงโครไนซ์และหลีกเลี่ยงค่าใช้จ่ายในการจัดการคิวและการสลับบริบทในช่องทาง
การโต้แย้งต่ำหรือสถานการณ์ที่ไม่ได้รับการแก้ไข
ในสภาพแวดล้อมที่มีการโต้แย้งต่ำการดำเนินการของ Mutex Lock และการปลดล็อคเกือบจะเป็นเพียงการดำเนินการอะตอมโดยไม่ต้องรอ กรณีที่ไม่ได้รับการแก้ไขคือที่ mutexes เปล่งประกายเนื่องจากการล็อคมีน้ำหนักเบาและมักจะไม่กระตุ้นการกำหนดเวลาระดับเคอร์เนล
อย่างไรก็ตามช่องทางมีค่าใช้จ่ายแม้ในการโต้แย้งต่ำเนื่องจากการส่ง/รับแต่ละครั้งเกี่ยวข้องกับการจัดการที่ซับซ้อนมากขึ้นบัฟเฟอร์และการซิงโครไนซ์ ดังนั้นสำหรับ goroutines จำนวนน้อยหรือในสถานการณ์ที่มีการโต้แย้งเพียงเล็กน้อย
พร้อมกันสูงพร้อมล็อคอย่างง่าย
ในสถานการณ์ที่ goroutines จำนวนมากดำเนินการส่วนสำคัญที่สั้นมากที่ปรับเปลี่ยนสถานะที่ใช้ร่วมกัน Mutexes ยังคงมีประสิทธิภาพมากกว่าช่อง เหตุผลสำคัญคือบล็อก mutexes ที่ต่อสู้กับ goroutines ในเคอร์เนลช่วยให้การกำหนดเวลาที่มีประสิทธิภาพและตื่นหนึ่ง goroutine เมื่อปลดล็อค ในทางกลับกันแชนเนลเกี่ยวข้องกับการกำหนดเวลา goroutine ที่ใช้งานอยู่และการจัดการคิวที่สร้างค่าใช้จ่ายภายใต้โหลด
ตัวอย่างเช่นมาตรฐานที่มี goroutines มากถึง 10 goroutines แสดงให้เห็นว่า mutexes เร็วขึ้นหลายเท่าและ mutexes ยังคงแข่งขันได้แม้จะมี goroutines หลายร้อย
การกระจายงานเมื่อการกลายพันธุ์ของรัฐน้อยที่สุด
สำหรับการจัดการชิ้นหรือรายการงาน Mutexes สามารถเร็วขึ้นเมื่อล็อคสั้น ๆ เพื่อป๊อปหรืองานผลักดัน แม้ว่าช่องทางนั้นเป็นธรรมชาติมากสำหรับการกระจายงาน แต่หากส่วนสำคัญสั้นและสถานะที่ใช้ร่วมกันต้องการการล็อคและปลดล็อคอย่างรวดเร็ว mutexes หลีกเลี่ยงค่าใช้จ่ายเพิ่มเติมของการประสานงานช่องและนำปริมาณงานที่ดีขึ้น
ในระบบโลกแห่งความเป็นจริงหลายอย่างเช่นกลุ่มคนงานหรือคิวงาน Mutexes สามารถง่ายขึ้นและเร็วขึ้นสำหรับการจัดการรายการงานเมื่อเทียบกับช่องทาง
ทำไม mutexes ถึงเร็วกว่าในกรณีเหล่านี้
- ค่าใช้จ่ายที่ต่ำกว่า: Mutexes ใช้คำแนะนำ CPU อะตอมโดยตรงสำหรับการล็อคและปลดล็อคบ่อยครั้งโดยไม่มีสวิตช์บริบทหรือการตัดสินใจกำหนดเวลาที่มีค่าใช้จ่ายสูง
- การปิดกั้นเคอร์เนลด้วยการเข้าคิว: การต่อสู้ goroutines นอนบน mutexes อย่างมีประสิทธิภาพสร้างคิวและตัวกำหนดตารางเวลาจะตื่นขึ้นมาอย่างต่อเนื่อง ช่องสัญญาณทำให้เกิดการปลุกและรูปแบบการตั้งเวลาที่ซับซ้อนมากขึ้น
- ไม่มีการส่งข้อความค่าใช้จ่าย: ช่องจะต้องจัดสรรบัฟเฟอร์หรือรายการคิวและการคัดลอกข้อมูลซึ่งไม่จำเป็นเมื่อความเป็นเจ้าของและการผูกขาดง่าย ๆ เพียงพอ
- การเข้าถึงหน่วยความจำโดยตรง: mutexes อนุญาตให้เข้าถึงหน่วยความจำโดยตรงภายในส่วนที่สำคัญในขณะที่ช่องต้องการการส่งข้อมูลผ่านสื่อการสื่อสารเพิ่มเลเยอร์ของทางอ้อมและเวลาแฝง
บริบทไม่เหมาะสำหรับช่องทาง
แม้ว่าช่องทางให้วิธีที่สง่างามและปลอดภัยในการสื่อสารระหว่าง goroutines และมีค่าสูงสำหรับการประมวลผลท่อและการจัดการเหตุการณ์ค่าใช้จ่ายของพวกเขาทำให้พวกเขาไม่เหมาะสมสำหรับการกลายพันธุ์ของรัฐที่ใช้ร่วมกันโดยย่อ
ช่องทางเหมาะอย่างยิ่งเมื่อซิงโครไนซ์การคำนวณที่ซับซ้อนที่เกี่ยวข้องกับ goroutines หลายตัวที่ข้อความที่ส่งผ่านความหมายเป็นธรรมชาติและเป็นประโยชน์ แต่สำหรับการล็อคอย่างง่าย Mutexes เปล่งประกาย
หลักฐานการทดลองและมาตรฐาน
- เกณฑ์มาตรฐานที่มีการซิงโครไนซ์ดั้งเดิมของ GO แสดงเคาน์เตอร์ Mutex ทำงานกับเวลาแฝงในช่วงนาโนวินาทีในขณะที่เคาน์เตอร์ช่องสัญญาณนั้นมีขนาดช้าลง (เช่น 0.8 ns เทียบกับ 60 ns ต่อการดำเนินการ)
- ประสิทธิภาพกลับด้านในระดับที่สูงมาก (เช่น goroutines หลายพัน) เมื่อช่องอาจมีประสิทธิภาพสูงกว่า mutexes ในบางกรณีเนื่องจากช่องทางหลีกเลี่ยงการล็อคค่าใช้จ่ายและโมเดลที่ดีกว่า
- ภายใต้การโต้แย้ง Mutexes มีประสิทธิภาพสูงกว่าสปินล็อคเนื่องจากประสิทธิภาพการกำหนดเวลาเคอร์เนลระดับ
- Mutexes หลีกเลี่ยงการจัดสรรหน่วยความจำและการสลับบริบทที่มีอยู่ในช่องทางซึ่งนำไปสู่การเพิ่มขึ้นอย่างมีนัยสำคัญในปริมาณงานและการใช้งาน CPU ที่ลดลงสำหรับการปกป้องตัวแปรที่ใช้ร่วมกัน
สรุปคำแนะนำกรณีการใช้งาน
- ใช้ mutexes เมื่อปกป้องหน่วยความจำที่ใช้ร่วมกันหรือสถานะที่ไม่แน่นอนเข้าถึงได้พร้อมกันโดยเฉพาะอย่างยิ่งหากส่วนสำคัญสั้นและเกี่ยวข้องกับการดำเนินการอย่างง่าย
- ใช้ช่องทางสำหรับการคำนวณการคำนวณท่อและสถาปัตยกรรมที่ขับเคลื่อนด้วยเหตุการณ์ที่ข้อความแสดงถึงสถานะหรืองานที่จะประมวลผลแบบอะซิงโครนัส
- สำหรับรหัสที่สำคัญต่อประสิทธิภาพที่เกี่ยวข้องกับการกลายพันธุ์ของสถานะโดยตรงโดยหลายเธรดหรือ goroutines mutexes มักจะให้ปริมาณงานที่เหนือกว่าและเวลาแฝงที่ต่ำกว่า
- พิจารณาช่องทางเมื่อตรรกะที่เกิดขึ้นพร้อมกันของคุณได้รับประโยชน์จากความหมายที่ส่งผ่านข้อความ แต่หลีกเลี่ยงความต้องการการล็อคแบบง่าย ๆ ที่มีความถี่สูง
การดำน้ำลึกทางเทคนิค
โดยทั่วไปแล้ว Mutexes ใช้การทำงานของอะตอมเช่น Compare-and-Swap (CAS) สำหรับการล็อคและปลดล็อคในพื้นที่ผู้ใช้และป้อนเคอร์เนลเมื่อมีการโต้แย้งเพื่อบล็อกเธรด สิ่งนี้จะช่วยลดการสลับบริบทและค่าใช้จ่ายในกรณีที่ไม่ได้รับการแก้ไข
ช่องทางใช้คิว FIFO สำหรับข้อความและมักได้รับการสนับสนุนจากบัฟเฟอร์ที่อาจปรับขนาดได้ การส่งช่องทางเกี่ยวข้องกับการตรวจสอบว่าตัวรับสัญญาณพร้อมหรือไม่การคัดลอกข้อมูลไปยังบัฟเฟอร์หรือการปิดกั้นและกำหนดเวลา goroutine ที่ได้รับ ขั้นตอนเหล่านี้เพิ่มค่าใช้จ่ายที่คูณด้วยความถี่ในการดำเนินการ
Mutexes นอนหลับต่อสู้กับเธรดและรักษาคิวเพื่อให้มีเพียงหนึ่งเธรดที่ตื่นขึ้นมาในแต่ละครั้ง ช่องทางอาจปลุกหลาย goroutines เมื่อมีข้อความพร้อมใช้งานซึ่งนำไปสู่การกำหนดเวลาที่ซับซ้อนมากขึ้นและค่าใช้จ่ายในการสลับบริบท
บทสรุป
โดยสรุป mutexes นั้นเร็วกว่าช่องทางในสถานการณ์ที่ต้องมีการกลายพันธุ์ของสถานะที่รวดเร็วง่ายและบ่อยครั้งที่มีการโต้แย้งต่ำหรือส่วนวิกฤตสั้น ๆ การใช้งานอะตอมที่มีน้ำหนักเบาของพวกเขาการปิดกั้นเคอร์เนลที่มีประสิทธิภาพและการตื่นของเธรดและการเข้าถึงหน่วยความจำโดยตรงให้ประสิทธิภาพที่เหนือกว่าเมื่อเทียบกับการตั้งเวลาการคัดลอกและข้อความที่ผ่านช่องทางเหนือศีรษะเกิดขึ้น ช่องทางเหมาะกว่าสำหรับการสื่อสารงานที่ซับซ้อนและประสานงาน goroutines แต่จ่ายค่าใช้จ่ายในความเร็วในการซิงโครไนซ์ดิบ
ความเข้าใจนี้ได้รับการสนับสนุนโดยเกณฑ์มาตรฐานหลายอย่างและตัวอย่างที่ใช้งานได้จริงจากระบบการผลิตและผลการทดลอง ดังนั้นการตัดสินใจระหว่าง mutexes และช่องทางควรขึ้นอยู่กับลักษณะของเวิร์กโหลดและความต้องการการซิงโครไนซ์โดยมี mutexes ต้องการความเร็วดิบในการปกป้องหน่วยความจำที่ใช้ร่วมกันและช่องที่สงวนไว้สำหรับการประสานงานระดับสูงและรูปแบบการสื่อสาร