Вот код, который у меня есть, но я не понимаю, что SemaphoreSlim
происходит.
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
}
}
Что ждет ss.WaitAsync();
и ss.Release();
делает?
Я предполагаю, что если я запускаю 50 потоков за раз, тогда напишу код, например, SemaphoreSlim ss = new SemaphoreSlim(10);
тогда он будет вынужден запускать 10 активных потоков за раз.
Когда один из 10 потоков завершается, запускается другой поток. Если я не прав, помогите мне разобраться с образцом ситуации.
Зачем await
нужен вместе с ss.WaitAsync();
? Что ss.WaitAsync();
делать?
Ответы:
Это правильно; использование семафора гарантирует, что эту работу будут выполнять не более 10 рабочих одновременно.
Вызов
WaitAsync
семафора создает задачу, которая будет завершена, когда этому потоку будет предоставлен «доступ» к этому токену.await
-исполнение этой задачи позволяет программе продолжить выполнение, когда это «разрешено». Наличие асинхронной версии, а не ее вызоваWait
, важно как для обеспечения того, чтобы метод оставался асинхронным, а не синхронным, так и для решения того факта, чтоasync
метод может выполнять код в нескольких потоках из-за обратных вызовов и т. Д. естественное сходство потоков с семафорами может быть проблемой.Примечание: постфикса
DoPollingThenWorkAsync
не должно быть,Async
потому что он на самом деле не асинхронный, а синхронный. Просто позвониDoPollingThenWork
. Это уменьшит путаницу для читателей.источник
Thread.Sleep
в исходном коде разрушит планировщик задач. Если вы не асинхронны с ядром, вы не асинхронны.В детском саду за углом они используют SemaphoreSlim, чтобы контролировать, сколько детей могут играть в спортивной комнате.
Они нарисовали на полу за пределами комнаты 5 пар следов ног.
Когда дети приходят, они оставляют обувь на свободных следах и входят в комнату.
Закончив игру, они выходят, собирают обувь и «освобождают» место для другого ребенка.
Если приходит ребенок и не остается следов, он идет поиграть в другое место или просто остается на некоторое время и время от времени проверяет (т.е. без приоритетов FIFO).
Когда учитель рядом, она «выпускает» дополнительный ряд из 5 следов на другой стороне коридора, так что еще 5 детей могут играть в комнате одновременно.
Там же есть те же "подводные камни" SemaphoreSlim ...
Если ребенок заканчивает игру и выходит из комнаты, не собрав обувь (не запускает «отпускание»), то слот остается заблокированным, даже если теоретически есть пустой слот. Однако обычно ребенка ругают.
Иногда один или два подлых ребенка прячут свою обувь в другом месте и входят в комнату, даже если все следы уже заняты (например, SemaphoreSlim «на самом деле» не контролирует, сколько детей находится в комнате).
Обычно это не заканчивается хорошо, так как переполненность комнаты, как правило, заканчивается тем, что дети плачут, а учитель полностью закрывает комнату.
источник
Хотя я согласен, что этот вопрос действительно относится к сценарию блокировки обратного отсчета, я подумал, что стоит поделиться этой ссылкой, которую я обнаружил, для тех, кто хочет использовать SemaphoreSlim в качестве простой асинхронной блокировки. Это позволяет использовать оператор using, который может сделать кодирование более аккуратным и безопасным.
http://www.tomdupont.net/2016/03/how-to-release-semaphore-with-using.html
Я сделал своп
_isDisposed=true
и_semaphore.Release()
вокруг в Dispose , хотя в случае , если она каким - то образом вызывается несколько раз.Также важно отметить, что SemaphoreSlim не является реентерабельной блокировкой, то есть, если один и тот же поток вызывает WaitAsync несколько раз, счетчик семафора каждый раз уменьшается. Короче говоря, SemaphoreSlim не поддерживает потоки.
Что касается вопросов о качестве кода, лучше поместить выпуск в конец попытки, чтобы гарантировать, что он всегда будет выпускаться.
источник