gpt4 book ai didi

c# - 使用信号量调用 WaitOne 是否会释放调用线程以执行其他工作?

转载 作者:行者123 更新时间:2023-11-30 12:38:24 25 4
gpt4 key购买 nike

我的应用程序需要每分钟为每个租户执行一些任务。这些是一劳永逸的操作,所以我不想使用 Parallel.ForEach 来处理这个问题。

相反,我循环遍历租户列表,并触发 ThreadPool.QueueUserWorkItem 来处理每个租户任务。

foreach (Tenant tenant in tenants)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessTenant), tenantAccount);
}

此代码在生产环境中运行良好,通常可以在 5 秒内处理 100 多个租户。

然而,在应用程序启动时,这会导致 100% 的 CPU 使用率,而像 EF 这样的东西会在启动过程中预热。为了限制这一点,我实现了一个信号量,如下所示:

private static Semaphore _threadLimiter = new Semaphore(4, 4);

想法是将此任务处理限制为只能使用一半的机器逻辑处理器。在我调用的 ProcessTenant 方法中:

try
{
_threadLimiter.WaitOne();

// Perform all minute-to-minute tasks
}
finally
{
_threadLimiter.Release();
}

在测试中,这似乎完全符合预期。启动时的 CPU 使用率保持在 50% 左右,似乎不会影响初始启动的速度。

所以问题主要围绕调用 WaitOne 时实际发生的情况。这是否释放线程以处理其他任务 - 类似于异步调用? MSDN 文档指出 WaitOne:“阻塞当前线程,直到当前 WaitHandle 收到信号。”

所以我只是担心这实际上不会允许我的网络应用程序在等待时继续使用这个被阻塞的线程,这会使整个练习变得毫无意义。

最佳答案

WaitOne 会阻塞线程,并且该线程将停止在 CPU 内核上调度,直到信号量发出信号为止。但是,您可能会长时间持有线程池中的大量线程(“长”如“长于 ~500 毫秒”)。这可能是一个问题,因为线程池增长非常缓慢,因此您可能会阻止应用程序的其他部分正确使用它。

如果您计划等待很长时间,您可以改用自己的线程:

foreach (Tenant tenant in tenants)
{
new Thread(ProcessTenant).Start(tenantAccount);
}

但是,您仍然在内存中为每个项目保留一个线程。虽然它们在信号量上休眠时不会占用 CPU,但它们仍在无用地使用 RAM(每个线程约 1MB)。相反,让一个专用线程等待信号量并根据需要将新项目入队:

// Run this on a dedicated thread
foreach (Tenant tenant in tenants)
{
_threadLimiter.WaitOne();
ThreadPool.QueueUserWorkItem(_ =>
{
try
{
ProcessTenant(tenantAccount);
}
finally
{
_threadLimiter.Release();
}
});
}

关于c# - 使用信号量调用 WaitOne 是否会释放调用线程以执行其他工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53059018/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com