C# 理解信号量LIM问题?
我这里有一个简单的测试代码,使用SemaphoreSlimC# 理解信号量LIM问题?,c#,async-await,task,semaphore,C#,Async Await,Task,Semaphore,我这里有一个简单的测试代码,使用SemaphoreSlim static SemaphoreSlim mSemaphore = new SemaphoreSlim(3); static async Task Main() { var tasks = new Task[5]; for (var i = 0; i < tasks.Length; i++) {
static SemaphoreSlim mSemaphore = new SemaphoreSlim(3);
static async Task Main()
{
var tasks = new Task[5];
for (var i = 0; i < tasks.Length; i++)
{
var taskNo = i;
tasks[i] = Task.Run(() => DoWork($"task{taskNo}"));
}
await Task.WhenAll(tasks);
}
static async Task DoWork(string taskName)
{
for (var i = 0; i < 3; i++)
{
mSemaphore.Wait();
Console.WriteLine($"{taskName}: doing {i}.");
await Task.Delay(1000);
mSemaphore.Release();
}
}
静态信号量lim mSemaphore=新信号量lim(3);
静态异步任务Main()
{
var任务=新任务[5];
对于(var i=0;iDoWork($“Task{taskNo}”);
}
等待任务。何时(任务);
}
静态异步任务DoWork(字符串taskName)
{
对于(变量i=0;i<3;i++)
{
mSemaphore.Wait();
WriteLine($“{taskName}:doing{i}.”);
等待任务。延迟(1000);
mSemaphore.Release();
}
}
如果我是正确的:在我的上下文中,我的信号量应该只允许3个任务完成它们的工作,然后它应该释放它们,然后它应该让我的其他2个任务完成它们的工作
问题
我对此进行了测试,但不幸的是,有时我会得到不同/错误的结果
下面是两个输出结果
输出
对
mSemaphore.Wait()
和mSemaphore.Release()
的调用在for
循环中。循环每次迭代后,每个任务都会释放信号量,然后再次尝试获取信号量
有鉴于此,没有什么可以阻止Task0、1或2在循环结束时释放信号量,以及task3获取信号量。释放它的任务将返回其循环的开始,并再次坐在mSemaphore.Wait()
上,等待另一个任务释放信号量
您的所有任务都在同一时间运行(除了非常小的初始延迟,可能),并且它们都具有相同的优先级(信号量LIM不能保证等待信号量的事物获取它的顺序——本质上是随机的,等待的任务将被赋予它)。因此,有时任务0、1和2在任务3得到信号量之前完成,有时事情以不同的顺序发生,这并不奇怪
如果您在每个任务尝试获取信号量、实际获取信号量、然后释放信号量的位置添加一些额外的日志记录,那么应该会更清楚一点——您将能够看到一个任务释放信号量,然后另一个任务立即拾取信号量)。方法:
阻止当前线程,直到它可以输入信号量lim
方法:
异步等待输入信号量lim
因为代码是异步的,所以应该使用WaitAsync
,而不是Wait
。通过在运行异步代码时阻塞线程,您将获得各种有趣的效果,而不是预期的行为。例如,在<代码>等待任务>延迟(1000)< /代码>之后,异步工作流可能继续运行在不同的线程上,或者可能不会,这取决于您不控制的条件。
长话短说,只要将
mSemaphore.Wait()
替换为Wait mSemaphore.WaitAsync()
,您就会没事了。只是一个友好的提示。SemaphoreSlim有一个异步版本,因此您的mSemaphore.Wait()
可以替换为wait mSemaphore.WaitAsync()因为由于您使用的延迟,您的方法已经是异步的。