Làm cách nào để chọn giữa Semaphore và SemaphoreSlim?


109

Các giao diện công cộng của chúng xuất hiện tương tự nhau. Các tài liệu hướng dẫn quốc gia rằng SemaphoreSlim là một sự thay thế nhẹ và không sử dụng semaphores Windows Kernel. Tài nguyên này nói rằng SemaphoreSlim nhanh hơn nhiều. Trong những tình huống nào thì SemaphoreSlim có ý nghĩa hơn Semaphore và ngược lại?


1
Semaphore luôn chuyển công việc cho OS. Điều đó làm cho nó tương đối đắt nếu semaphore không bị tranh chấp mạnh mẽ, cuộc gọi hạt nhân dễ dàng tốn 400 nano giây. Ưu tiên mỏng đầu tiên cố gắng làm điều đó với giá rẻ bằng một biến chia sẻ, chỉ gọi vào HĐH khi điều đó không hoạt động. Bạn luôn thích giá rẻ, ngoại trừ trường hợp góc khuất mà semaphore cần được chia sẻ bởi nhiều tiến trình.
Hans Passant

Câu trả lời:


64

Một sự khác biệt là SemaphoreSlimnó không cho phép các semaphores được đặt tên, có thể là toàn hệ thống. Điều này có nghĩa là không thể sử dụng SemaphoreSlim để đồng bộ hóa quá trình chéo.

Tài liệu MSDN cũng chỉ ra rằng SemSlim nên được sử dụng khi "thời gian chờ đợi sẽ rất ngắn". Điều đó thường kết hợp độc đáo với ý tưởng rằng phiên bản mỏng nhẹ hơn đối với hầu hết các đánh đổi.


66
Tôi ước MS đã viết một cái gì đó về những gì sẽ xảy ra khi thời gian chờ đợi không phải là "rất ngắn".
John Reynolds

79
... hoặc những gì có nghĩa là "rất ngắn"
Richard Szalay

9
Tùy thuộc vào hệ thống, 1 micro giây cho Semaphore và 1/4 micro giây cho SemaphoreSlim để thực hiện WaitOne hoặc Release ["C # 5.0 in a Nutshell". 890] Vì vậy, có lẽ đó là những gì họ có nghĩa là thời gian chờ đợi rất ngắn?
David Sherret

2
@dhsto Tham khảo tốt! Nhưng tôi đoán rằng bài viết được liên kết có nghĩa là "khi thời gian chờ đợi để truy cập tài nguyên được chia sẻ là rất ngắn" - tức là tài nguyên sẽ không được sử dụng độc quyền trong thời gian dài - chứ không phải là thời gian chờ cho chính mã semaphore? Mã semaphore sẽ luôn được thực thi bất kể tài nguyên được giữ trong bao lâu.
culix

4
@culix Nhìn vào nguồn cho Semaphore so với SemaphoreSlim Tôi nghi ngờ lý do chính mà SemaphoreSlim chỉ nên được sử dụng cho các lần chờ "rất ngắn" là vì nó sử dụng thời gian chờ quay vòng. Điều này phản hồi nhanh hơn, nhưng ngốn rất nhiều CPU và sẽ lãng phí trong thời gian chờ lâu hơn, nơi phản hồi tức thời ít quan trọng hơn. Thay vào đó, Semaphore chặn luồng.
r2_118

17

Tài liệu MSDN mô tả sự khác biệt.

Trong một câu:

  • Lớp SemaphoreSlim đại diện cho một semaphore nhanh, nhẹ có thể được sử dụng để chờ trong một quá trình duy nhất khi thời gian chờ dự kiến ​​là rất ngắn.

1
Để thêm vào điều này, hãy sử dụng SemaphoreSlim trong mọi trường hợp mà ứng dụng của bạn là quy trình duy nhất trên máy tính của bạn cần truy cập Semaphore đó.
Austin Salgat

2
@Salgat Tại sao bạn làm như vậy? Như đã nêu trong các câu trả lời khác, SemaphoreSlimđược triển khai bằng SpinWait, vì vậy nếu bạn chờ đợi nó nhiều, bạn sẽ lãng phí rất nhiều thời gian của CPU. Điều này thậm chí không phải là một ý kiến ​​hay nếu quy trình của bạn là quy trình duy nhất trên máy tính.
M.Stramm

Từ tài liệu MSDN, "Lớp SemaphoreSlim là semaphore được khuyến nghị để đồng bộ hóa trong một ứng dụng.". Trừ những trường hợp đặc biệt, bạn nên mặc định sử dụng SemaphoreSlim nếu chỉ có một tiến trình đang sử dụng semaphore đó. Các ngoại lệ đặc biệt thường tồn tại cho bất kỳ kiểu dữ liệu đồng thời nào, điều này không cần phải nói.
Austin Salgat

17

SemaphoreSlim dựa trên SpinWait và Monitor, do đó, luồng chờ lấy khóa sẽ đốt các chu kỳ CPU trong một thời gian với hy vọng có được khóa trước khi chuyển sang luồng khác. Nếu điều đó không xảy ra, thì các luồng cho phép hệ thống chuyển đổi ngữ cảnh và thử lại (bằng cách ghi một số chu kỳ CPU) sau khi hệ điều hành lên lịch cho luồng đó một lần nữa. Với thời gian chờ lâu, mô hình này có thể ghi qua một lượng đáng kể chu kỳ CPU. Vì vậy, trường hợp tốt nhất cho việc triển khai như vậy là khi hầu hết thời gian không có thời gian chờ đợi và bạn gần như có thể lấy được khóa ngay lập tức.

Semaphore dựa vào việc thực hiện trong nhân hệ điều hành, vì vậy mỗi khi bạn có được khóa, bạn tốn khá nhiều chu kỳ CPU, nhưng sau đó luồng chỉ ngủ trong khoảng thời gian cần thiết để lấy khóa.


12

Về tranh cãi "thời gian ngắn":

Ít nhất tài liệu SemaphoreSlim MSDN nói rằng

Lớp SemaphoreSlim là semaphore được khuyến nghị để đồng bộ hóa trong một ứng dụng.

trong phần Nhận xét. Phần tương tự cũng cho biết sự khác biệt chính giữa Semaphore và SemaphoreSlim:

SemaphoreSlim là một giải pháp thay thế nhẹ cho lớp Semaphore không sử dụng semaphores hạt nhân Windows. Không giống như lớp Semaphore, lớp SemaphoreSlim không hỗ trợ các semaphores hệ thống được đặt tên. Bạn chỉ có thể sử dụng nó như một semaphore cục bộ.


1
Thông tin chi tiết: [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/...
Marco Sulla

0

Tôi đã xem mã nguồn ở đây và đây là những gì tôi nghĩ ra:

  1. Cả Semaphore và SemaphoreSlim đều xuất phát từ WaitHandle sử dụng nội bộ Win32 native. Đó là lý do tại sao bạn cần Loại bỏ () cả hai. Vì vậy, quan điểm cho rằng Slim nhẹ là nghi ngờ.

  2. SemaphoreSlim sử dụng SpinWait nội bộ trong khi Semaphore thì không. Điều đó cho tôi biết rằng trong trường hợp chờ đợi lâu, ít nhất Semaphore nên làm tốt hơn theo nghĩa là nó sẽ không làm nghẹt CPU của bạn.


2
SemaphoreSlim không có nguồn gốc từ WaitHandle. Trên thực tế, nó được tạo ra với một mục tiêu duy nhất - để loại bỏ xuất phát từ WaitHandle, là nguyên thủy của không gian hạt nhân, trong các tác vụ mà bạn chỉ cần đồng bộ hóa các hoạt động bên trong một quy trình.
Igor V Savchenko
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.