【问题标题】:Understanding SemaphoreSlim problems?了解 SemaphoreSlim 问题?
【发布时间】:2019-10-20 15:33:47
【问题描述】:

我在这里使用 SemaphoreSlim 编写了一个简单的测试代码

        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();
            }
        }

如果我是正确的:在我的上下文中,我的信号量应该只允许 3 个任务来完成它们的工作,然后它应该释放它们,然后它应该让我的其他 2 个任务来完成它们的工作。

问题

我对此进行了测试,但不幸的是,有时我会得到不同/错误的结果。

这里有 2 个输出结果。

输出

【问题讨论】:

  • 只是一个友好的提示。 SemaphoreSlim 有一个异步版本,因此您的 mSemaphore.Wait(); 可以替换为 await mSemaphore.WaitAsync();,因为由于您使用的延迟,您的方法已经是异步的。

标签: c# async-await task semaphore


【解决方案1】:

mSemaphore.Wait()mSemaphore.Release() 的调用你的for 循环中。在循环的每次迭代之后,每个任务都会释放信号量,然后再次尝试获取它。

鉴于此,没有什么可以阻止任务 0、1 或 2 在循环结束时释放信号量,并阻止任务 3 获取信号量。释放它的任务将回到其循环的开头,并再次坐在mSemaphore.Wait() 上,等待另一个任务释放信号量。

您的所有任务都在同时运行(除了很小的初始延迟,可能),并且它们都具有相同的优先级(SemaphoreSlim 不保证等待信号量的事物获取它的顺序——哪个等待任务将被赋予它本质上是随机的)。因此,有时任务 0、1 和 2 在任务 3 获得信号量之前完成也就不足为奇了,有时事情会以不同的顺序发生。

如果您在每个任务尝试获取信号量时添加一些额外的日志记录,实际获取它,然后释放它,这应该会更清楚一些——您将能够看到一个任务释放它,然后另一个任务立即拿起它)。

【讨论】:

    【解决方案2】:

    方法SemaphoreSlim.Wait

    阻塞当前线程,直到它可以进入SemaphoreSlim

    方法SemaphoreSlim.WaitAsync

    异步等待输入SemaphoreSlim

    由于您的代码是异步的,您应该使用WaitAsync,而不是Wait。通过在运行异步代码时阻塞线程,您将获得各种有趣的效果,而不是您期望的行为。例如,在await Task.Delay(1000) 之后,您的异步工作流可能会继续在不同的线程上运行,也可能不会,这取决于您无法控制的条件。

    长话短说,只需将mSemaphore.Wait() 替换为await mSemaphore.WaitAsync() 即可。

    【讨论】:

      猜你喜欢
      • 2014-06-08
      • 2011-06-07
      • 2016-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-19
      相关资源
      最近更新 更多