Oto kod, który mam, ale nie rozumiem, co SemaphoreSlim
robi.
async Task WorkerMainAsync()
{
SemaphoreSlim ss = new SemaphoreSlim(10);
List<Task> trackedTasks = new List<Task>();
while (DoMore())
{
await ss.WaitAsync();
trackedTasks.Add(Task.Run(() =>
{
DoPollingThenWorkAsync();
ss.Release();
}));
}
await Task.WhenAll(trackedTasks);
}
void DoPollingThenWorkAsync()
{
var msg = Poll();
if (msg != null)
{
Thread.Sleep(2000); // process the long running CPU-bound job
}
}
Co czeka ss.WaitAsync();
i co ss.Release();
robi?
Wydaje mi się, że jeśli uruchomię 50 wątków na raz, a potem napiszę kod w SemaphoreSlim ss = new SemaphoreSlim(10);
ten sposób, będzie zmuszony do uruchomienia 10 aktywnych wątków na raz.
Gdy jeden z 10 wątków zostanie zakończony, rozpocznie się kolejny wątek. Jeśli nie mam racji, pomóż mi zrozumieć przykładową sytuację.
Dlaczego jest await
potrzebny wraz z ss.WaitAsync();
? Co robi ss.WaitAsync();
?
Odpowiedzi:
To jest poprawne; zastosowanie semafora gwarantuje, że nie będzie więcej niż 10 pracowników wykonujących tę pracę w tym samym czasie.
Wywołanie
WaitAsync
semafora powoduje utworzenie zadania, które zostanie zakończone, gdy wątek uzyska „dostęp” do tego tokenu.await
- wykonanie tego zadania pozwala programowi kontynuować wykonywanie, gdy jest to „dozwolone”. Posiadanie wersji asynchronicznej, a nie wywoływanieWait
, jest ważne zarówno dla zapewnienia, że metoda pozostanie asynchroniczna, a nie synchroniczna, a także zajmuje się faktem, żeasync
metoda może wykonywać kod w kilku wątkach ze względu na wywołania zwrotne, itd. problem może stanowić naturalne powinowactwo nici do semaforów.Na marginesie:
DoPollingThenWorkAsync
nie powinien miećAsync
postfiksu, ponieważ nie jest w rzeczywistości asynchroniczny, jest synchroniczny. Po prostu to nazwijDoPollingThenWork
. Zmniejszy to zamieszanie wśród czytelników.źródło
Thread.Sleep
oryginalnym kodzie zdewastowałoby harmonogram zadań. Jeśli nie jesteś asynchroniczny z rdzeniem, nie jesteś asynchroniczny.W przedszkolu za rogiem używają SemaphoreSlim, aby kontrolować, ile dzieci może bawić się w pokoju wf.
Namalowali na podłodze poza pokojem 5 par śladów.
Kiedy przyjeżdżają dzieci, zostawiają buty na wolnych śladach i wchodzą do pokoju.
Gdy skończą grać, wychodzą, zbierają buty i „uwalniają” miejsce dla innego dziecka.
Jeśli dziecko przyjeżdża i nie ma żadnych śladów, idzie pobawić się gdzie indziej lub po prostu zostaje na chwilę i od czasu do czasu sprawdza (tj. Brak priorytetów FIFO).
Kiedy nauczyciel jest w pobliżu, „wypuszcza” dodatkowy rząd 5 śladów po drugiej stronie korytarza, tak że 5 więcej dzieci może bawić się w pokoju w tym samym czasie.
Ma też te same „pułapki” SemaphoreSlim ...
Jeśli dziecko zakończy grę i wyjdzie z pokoju bez zabrania butów (nie powoduje to „wypuszczenia”), to slot pozostaje zablokowany, mimo że teoretycznie jest pusty. Jednak dzieciak zwykle jest wytykany.
Czasami jedno lub dwoje podstępnych dzieciaków chowa swoje buty w innym miejscu i wchodzi do pokoju, nawet jeśli wszystkie ślady są już zabrane (tzn. SemaphoreSlim nie kontroluje „naprawdę” liczby dzieci w pokoju).
Zwykle nie kończy się to dobrze, ponieważ przepełnienie pokoju kończy się płaczem dzieci i całkowitym zamknięciem pokoju przez nauczyciela.
źródło
Chociaż zgadzam się, że to pytanie naprawdę odnosi się do scenariusza blokady odliczania, pomyślałem, że warto udostępnić ten link, który odkryłem dla tych, którzy chcą używać SemaphoreSlim jako prostej blokady asynchronicznej. Pozwala na użycie instrukcji using, która może uczynić kodowanie czystszym i bezpieczniejszym.
http://www.tomdupont.net/2016/03/how-to-release-semaphore-with-using.html
Zamieniłem się
_isDisposed=true
i_semaphore.Release()
zmieniłem w jego Dispose, na wypadek, gdyby w jakiś sposób został wezwany wiele razy.Należy również zauważyć, że SemaphoreSlim nie jest blokadą ponownego wejścia, co oznacza, że jeśli ten sam wątek wywołuje WaitAsync wiele razy, licznik semafora jest zmniejszany za każdym razem. W skrócie SemaphoreSlim nie jest świadomy wątku.
Jeśli chodzi o pytania dotyczące jakości kodu, lepiej jest umieścić wydanie na końcu próby, aby mieć pewność, że zawsze zostanie wydane.
źródło