需要了解 SemaphoreSlim 的用法

这是我的代码,但我不明白 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
}
}

await ss.WaitAsync();ss.Release();做什么?

我想如果我一次运行50个线程,然后编写像 SemaphoreSlim ss = new SemaphoreSlim(10);这样的代码,那么它将被迫一次运行10个活动线程。

当10个线程中的一个完成时,将启动另一个线程。如果我不正确,然后帮助我了解与样品的情况。

为什么 awaitss.WaitAsync();一起需要? ss.WaitAsync();做什么?

112445 次浏览

我猜如果我一次运行50个线程,那么像 SemaphoreSlim ss = new SemaphoreSlim (10)这样的代码会强制一次运行10个活动线程

这是正确的; 使用信号量可以确保同时执行这项工作的工作人员不超过10人。

在信号量上调用 WaitAsync将生成一个任务,该任务将在该线程被授予对该令牌的“访问权限”时完成。await-让程序在“允许”执行时继续执行该任务。拥有一个异步版本,而不是调用 Wait,对于确保方法保持异步而不是同步非常重要,同时也处理了这样一个事实: 由于回调,async方法可以跨多个线程执行代码,因此与信号量的自然线程关联可能是一个问题。

附注: DoPollingThenWorkAsync不应该有 Async后缀,因为它实际上不是异步的,而是同步的。就叫它 DoPollingThenWork。它将减少读者的困惑。

虽然我承认这个问题确实与倒计时锁场景有关,但我认为值得分享这个链接,它是我为那些希望使用 SemaphoreSlim 作为一个简单的异步锁的人发现的。它允许您使用 using 语句,这可以使编码更加简洁和安全。

Http://www.tomdupont.net/2016/03/how-to-release-semaphore-with-using.html

我在它的 Dispose 中交换了 _isDisposed=true_semaphore.Release(),以防它被多次调用。

同样需要注意的是,SemaphoreSlim 不是一个可重入锁,这意味着如果同一个线程多次调用 WaitAsync,信号量的计数每次都会减少。简而言之,SemaphoreSlim 不知道线程。

关于代码质量的问题,最好是把版本放在最后的尝试中——最后确保它总是被发布。

在转角处的幼儿园里,他们使用 SemaphoreSlim 来控制有多少孩子可以在体育教室里玩耍。

他们在房间外的地板上画了5对脚印。

当孩子们到达时,他们把鞋子留在一对免费的脚印上,然后进入房间。

一旦他们玩完了,他们出来,收集他们的鞋子和“释放”另一个孩子的插槽。

如果一个孩子来了,没有留下任何脚印,他们就会去别的地方玩,或者只是在附近逗留一会儿,时不时地检查一下(也就是说,没有先进先出优先权)。

当老师在的时候,她会在走廊的另一边“释放”一排额外的5个脚印,这样就可以让另外5个孩子同时在房间里玩耍。

它也有同样的“陷阱”信号苗条..。

如果一个孩子玩完了,离开了房间而没有收集鞋子(不触发“释放”) ,那么插槽仍然被堵塞,即使理论上有一个空的插槽。不过这孩子通常会被责骂。

有时候一两个鬼鬼祟祟的孩子会把鞋子藏在别的地方,然后进入房间,即使所有的脚印都已经留下了(例如,SemaphoreSlim 并不“真的”控制房间里有多少个孩子)。

这通常不会有好结果,因为过度拥挤的教室往往导致孩子们哭泣,老师完全关闭了教室。