计时器回调中的锁定语句=潜在的线程饥饿?

问题描述 投票:0回答:1

我的库有多个计时器(可以有数百个),它们都调用相同的逻辑(这是缓存清理,但这并不重要)。

这个逻辑非常消耗 CPU 资源,所以我引入了一个

lock
语句,以防止多个线程同时加载 CPU:

_timer = new Timer(EvictExpiredItems, null, interval, interval);

private void EvictExpiredItems(object state)
{
    lock (_globalStaticLock)
    {
        DoStuff();
    }
}

但是我担心的是 - 因为计时器回调是在线程池线程上执行的(?),而我实际上阻塞了该线程,这可能会导致线程饥饿(例如,在 ASP.NET 应用程序中)。

这是一个合理的担忧吗?

我的解决方案是进行计时器回调

async
并使用
SempahoreSlim
而不是
lock

private async void EvictExpiredItems(object state)
{
    await _semaphoreSlim.WaitAsytnc(); //static semaphore var
    try
    {
        DoStuff();
    }
    finally
    {
         _semaphoreSlim.Release();
    }

}

这是一个合理的担忧吗?这是一个有效的解决方案吗?

c# timer threadpool
1个回答
0
投票

是的,在计时器回调中使用

lock
,您将面临线程池饥饿的风险。
Timer
组件调用
ThreadPool
上的回调,因此如果
DoStuff
花费大量时间,并且在此期间回调调用比
ThreadPool
中可用的线程多,
ThreadPool
将变得饱和。这意味着新的工作请求不会立即得到满足,而是只有在线程可用时才会得到满足。
ThreadPool
有一种算法,可以在线程太少或太多时创建或销毁线程,因此饱和事件很少会导致死锁,但应用程序的性能和响应能力可能会受到明显的影响。如果我们谈论的是 ASP.NET 应用程序,那么应用程序的可扩展性也可能会受到严重损害。

我的建议是重新考虑你正在做的事情。您说您的应用程序有数百个计时器,它们都调用相同的逻辑。这对我来说听起来很恐怖。

© www.soinside.com 2019 - 2024. All rights reserved.