使用异步任务和信号量的僵局
我们正在运行ASP.NET 6 WebApplication,并在僵局中遇到了奇怪的问题。 经过数周的操作,该应用程序突然冻结了,似乎这可能是由于我们使用Smaphoreslim类的锁定机制引起的。
我试图用简单的测试项目重现这个问题,并发现了一些奇怪的东西。
以下代码只是启动1000个任务,每个任务都在进行一些工作(请求信号量表,等待10 ms并发布信号量)。
我希望此代码只会执行一个任务。但是,由于 dowork
方法的第一个呼叫中的僵局(在等待任务。
有人知道为什么这会导致僵局吗?我尝试使用 threadpool.queueuserworkitem
而不是 task.run
和 thread.sleep
而不是 task> task.delay 这是按预期工作的。但是,一旦我使用任务就停止工作。
这是完整的代码刺:
internal class Program
{
static int timeoutSec = 60;
static SemaphoreSlim semaphore = new SemaphoreSlim(1);
static int numPerIteration = 1000;
static int iteration = 0;
static int doneCounter = numPerIteration;
static int successCount = 0;
static int failedCount = 0;
static Stopwatch sw = new Stopwatch();
static Random rnd = new Random();
static void Main(string[] args)
{
Task.WaitAll(TestUsingTasks());
}
static async Task TestUsingTasks()
{
while (true)
{
var tasks = new List<Task>();
if (doneCounter >= numPerIteration)
{
doneCounter = 0;
if (iteration >= 1)
{
Log($"+++++ FINISHED TASK ITERATION {iteration} - SUCCESS: {successCount} - FAILURES: {failedCount} - Seconds: {sw.Elapsed.TotalSeconds:F1}", ConsoleColor.Magenta);
}
iteration++;
sw.Restart();
for (int i = 0; i < numPerIteration; i++)
{
// Start indepdent tasks to do some work
Task.Run(async () =>
{
if (await DoWork())
{
successCount++;
}
else
{
failedCount++;
}
doneCounter++;
});
}
}
await Task.Delay(10);
}
}
static async Task<bool> DoWork()
{
if (semaphore.Wait(timeoutSec * 1000)) // Request the semaphore to ensure that one 1 task at a time can enter
{
Log($"Got handle for {iteration} within {sw.Elapsed.TotalSeconds:F1}", ConsoleColor.Green);
var totalSec = sw.Elapsed.TotalSeconds;
await Task.Delay(10); // Wait for 10ms to simulate some work => Deadlock seems to happen here
Log($"RELEASING LOCK handle for {iteration} within {sw.Elapsed.TotalSeconds:F1}. WAIT took " + (sw.Elapsed.TotalSeconds - totalSec) + " seconds", ConsoleColor.Gray);
semaphore.Release();
return true;
}
else
{
Log($"ERROR: TASK handle failed for {iteration} within {sw.Elapsed.TotalSeconds:F1} sec", ConsoleColor.Red);
return false;
}
}
static void Log(string message, ConsoleColor color)
{
Console.ForegroundColor = color;
Console.WriteLine(message);
Console.ForegroundColor = ConsoleColor.White;
}
}
预先感谢!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我认为这不是僵局,而是a 问题。如果您等待足够长的时间,您将看到线程能够不时完成模拟等待。
此处的快速修复是使用非块
waitasync
用等待
来调用:还要注意:
Wait ..
中包装代码。试用
阻止并在最后发布信号量
。互锁。Increment
。I would argue that it is not deadlock but a thread starvation issue. If you wait long enough you will see that threads will be able to finish the simulation wait from time to time.
The quick fix here is using non-blocking
WaitAsync
call withawait
:Also note:
Wait..
intotry-finally
block and release the semaphore in thefinally
.Interlocked.Increment
.