c# – 使用Semaphore调用WaitOne是否释放调用线程来执行其他工作?
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了c# – 使用Semaphore调用WaitOne是否释放调用线程来执行其他工作?,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含1872字,纯文字阅读大概需要3分钟。
内容图文
我的应用程序需要每分钟为每个租户执行一些任务.这些是即发即弃操作,因此我不想使用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 ms”).这可能是一个问题,因为线程池增长非常缓慢,因此您可能会阻止应用程序的其他部分正确使用它.
如果您打算等待大量时间,可以使用自己的线程代替:
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# – 使用Semaphore调用WaitOne是否释放调用线程来执行其他工作?全部内容,希望文章能够帮你解决c# – 使用Semaphore调用WaitOne是否释放调用线程来执行其他工作?所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。