ฉันจะเลือกระหว่าง Semaphore และ SemaphoreSlim ได้อย่างไร?


109

อินเทอร์เฟซสาธารณะของพวกเขาดูเหมือนกัน เอกสารระบุว่า SemaphoreSlim เป็นทางเลือกที่มีน้ำหนักเบาและไม่ได้ใช้สัญญาณเคอร์เนลของ Windows แหล่งข้อมูลนี้ระบุว่า SemaphoreSlim เร็วกว่ามาก ในสถานการณ์ใดที่ SemaphoreSlim มีความหมายมากกว่า Semaphore และในทางกลับกัน


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

คำตอบ:


64

ความแตกต่างอย่างหนึ่งคือSemaphoreSlimไม่อนุญาตให้มีการตั้งชื่อ semaphores ซึ่งสามารถใช้ได้ทั้งระบบ นี่หมายความว่าไม่สามารถใช้ SemaphoreSlim สำหรับการซิงโครไนซ์ข้ามกระบวนการ

เอกสาร MSDNยังระบุว่าควรใช้ SemSlim เมื่อ "เวลารอคาดว่าจะสั้นมาก" นั่นมักจะประกบกันอย่างดีกับความคิดที่ว่ารุ่นบางนั้นมีน้ำหนักเบากว่าสำหรับการแลกเปลี่ยนส่วนใหญ่


66
ฉันหวังว่า MS จะเขียนบางอย่างเกี่ยวกับสิ่งที่เกิดขึ้นเมื่อเวลารอไม่ "สั้นมาก"
John Reynolds

79
... หรือความหมาย "สั้นมาก"
Richard Szalay

9
ทั้งนี้ขึ้นอยู่กับระบบ 1 ไมโครวินาทีสำหรับ Semaphore และ 1/4 ไมโครวินาทีสำหรับ SemaphoreSlim เพื่อทำ WaitOne หรือ Release ["C # 5.0 in a Nutshell" หน้า 890] นั่นอาจเป็นความหมายของเวลารอที่สั้นมาก?
David Sherret

2
@dhsto อ้างอิงดี! แต่ฉันคาดเดาว่าบทความที่เชื่อมโยงหมายความว่า "เมื่อเวลารอเพื่อเข้าถึงทรัพยากรที่แชร์นั้นสั้นมาก" นั่นคือทรัพยากรจะไม่ถูกใช้งานเป็นระยะเวลานานโดยเฉพาะ - แทนที่จะหมายถึงเวลาในการรอสำหรับรหัสสัญญาณเอง? โค้ดเซมาฟอร์จะทำงานตลอดเวลาไม่ว่าทรัพยากรจะถูกล็อคไว้นานแค่ไหนก็ตาม
culix

4
@culix ดูที่มาของ Semaphore เทียบกับ SemaphoreSlim ฉันสงสัยว่าสาเหตุหลักที่ควรใช้ SemaphoreSlim สำหรับการรอที่ "สั้นมาก" นั้นเป็นเพราะมันใช้การรอแบบหมุน สิ่งนี้ตอบสนองได้ดีกว่า แต่กิน CPU มากและจะเป็นการสิ้นเปลืองสำหรับการรอนานขึ้นซึ่งการตอบสนองในทันทีมีความสำคัญน้อยกว่า เซมาฟอร์บล็อกเธรดแทน
r2_118

17

เอกสาร MSDNอธิบายความแตกต่าง

ในประโยคเดียว:

  • คลาส SemaphoreSlim แสดงถึงเซมาฟอร์ที่มีน้ำหนักเบาและรวดเร็วซึ่งสามารถใช้สำหรับการรอภายในกระบวนการเดียวเมื่อคาดว่าเวลารอจะสั้นมาก

1
ในการเพิ่มสิ่งนี้ให้ใช้ SemaphoreSlim ในทุกกรณีที่แอปพลิเคชันของคุณเป็นกระบวนการเดียวบนคอมพิวเตอร์ของคุณที่จำเป็นต้องเข้าถึง Semaphore นั้น
Austin Salgat

2
@Salgat จะทำแบบนั้นทำไม? ดังที่ระบุไว้ในคำตอบอื่น ๆSemaphoreSlimจะใช้งานโดยใช้ SpinWait ดังนั้นหากคุณรอมากคุณจะเสียเวลา CPU มาก ซึ่งไม่ใช่ความคิดที่ดีเลยหากกระบวนการของคุณเป็นกระบวนการเดียวในคอมพิวเตอร์
M.Stramm

จากเอกสาร MSDN "คลาส SemaphoreSlim คือเซมาฟอร์ที่แนะนำสำหรับการซิงโครไนซ์ภายในแอปเดียว" ยกเว้นกรณีพิเศษคุณควรใช้ SemaphoreSlim เป็นค่าเริ่มต้นหากมีเพียงกระบวนการเดียวที่ใช้สัญญาณนั้น โดยทั่วไปมีข้อยกเว้นพิเศษสำหรับข้อมูลประเภทใด ๆ ที่เกิดขึ้นพร้อมกันซึ่งไม่ต้องพูด
Austin Salgat

17

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

Semaphore อาศัยการใช้งานในเคอร์เนลระบบปฏิบัติการดังนั้นทุกครั้งที่คุณได้รับการล็อกคุณจะใช้รอบ CPU ค่อนข้างมาก แต่หลังจากนั้นเธรดก็จะเข้าสู่โหมดสลีปนานเท่าที่จำเป็นเพื่อให้ได้ล็อก


12

เกี่ยวกับการโต้เถียง "ช่วงเวลาสั้น ๆ ":

อย่างน้อยเอกสาร SemaphoreSlim MSDNระบุว่า

คลาส SemaphoreSlim เป็นสัญญาณที่แนะนำสำหรับการซิงโครไนซ์ภายในแอพเดียว

ในส่วนหมายเหตุ ส่วนเดียวกันยังบอกความแตกต่างหลักระหว่าง Semaphore และ SemaphoreSlim:

SemaphoreSlim เป็นทางเลือกที่มีน้ำหนักเบาสำหรับคลาส Semaphore ที่ไม่ใช้เซมาโฟร์เคอร์เนลของ Windows ซึ่งแตกต่างจากคลาส Semaphore คลาส SemaphoreSlim ไม่สนับสนุนเซมาโฟร์ระบบที่มีชื่อ คุณสามารถใช้เป็นสัญญาณท้องถิ่นเท่านั้น


1
รายละเอียดเพิ่มเติม: [SemaphoreSlim and other locks] use busy spinning for brief periods before they put the thread into a true Wait state. When wait times are expected to be very short, spinning is far less computationally expensive than waiting, which involves an expensive kernel transition: dotnet.github.io/docs/essentials/collections/...
มาร์โคซัลล่า

0

ฉันดูซอร์สโค้ดที่นี่และนี่คือสิ่งที่ฉันคิดขึ้น:

  1. ทั้ง Semaphore และ SemaphoreSlim มาจาก WaitHandle ซึ่งใช้ภายใน Win32 ที่จับแบบเนทีฟ นั่นคือเหตุผลที่คุณต้องกำจัด () ทั้งสองอย่าง ดังนั้นความคิดที่ว่า Slim มีน้ำหนักเบาจึงเป็นที่น่าสงสัย

  2. SemaphoreSlim ใช้ SpinWait ภายในในขณะที่ Semaphore ไม่ใช้ นั่นบอกฉันว่าในกรณีที่คาดว่าการรอจะนาน Semaphore ควรทำได้ดีกว่าอย่างน้อยก็ในแง่ที่ว่ามันจะไม่ทำให้ CPU ของคุณขาดอากาศหายใจ


2
SemaphoreSlim ไม่ได้มาจาก WaitHandle จริงๆแล้วมันถูกสร้างขึ้นโดยมีเป้าหมายเดียว - เพื่อกำจัดการได้มาจาก WaitHandle ซึ่งเป็นแบบดั้งเดิมของพื้นที่เคอร์เนลในงานที่คุณต้องซิงโครไนซ์การดำเนินการภายในกระบวนการเดียวเท่านั้น
Igor V Savchenko
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.