c# - 即使 ThreadPool.GetAvailableThreads() 表示丰富,任务也会受到调度缓慢的影响吗?
问题描述
我们有一个在生产中运行的服务器,它接收数据,放入queueA
. 另一个线程一次从 中获取一个项目queueA
,对其进行处理并将其放入queueB
.
此设置实际上是镜像的,因此两个镜像服务器接收完全相同的数据并以相同的方式处理它们,在主动-主动冗余设置中。
大约一年一次,其中一台服务器的消息大量堆积在queueA
.
所以问题似乎是queueA
从queueB
. 除了(完全没有必要)使用 Task 库(如下面的精简版和简化版所示)之外,没有太多事情要做。
public IAsyncResult BeginReceive()
{
Task<object> task = new Task<object>(_ =>
{
object message;
if (!queueA.TryDequeue(out message))
{
if (queueA.IsEmpty)
waitQueueA.WaitOne(10); // waitQueueA is properly signaled whenever an item is put into queueA
}
return message;
}, null, TaskCreationOptions.PreferFairness);
task.ContinueWith((t) =>
{
object receivedMessage = t.Result;
if (receivedMessage != null)
{
lock (bLock) // bLock is only used by this piece of code
{
queueB.Enqueue(receivedMessage);
}
}
else
{
Thread.Sleep(1);
}
BeginReceive(OnReceive, channel);
});
task.Start();
return task;
}
public object EndReceive(IAsyncResult result)
{
Task<object> task = (Task<object>) result;
return task.Result;
}
忽略代码的许多特性(就我个人而言,我会为此创建一个单独的专用线程,并在一个大while (true) { }
循环中执行上述所有操作,而不Task
涉及任何 s),这种情况可能会使其性能如此糟糕,以至于循环旋转以 15 次迭代/秒的性能为主,最高低于 50 次迭代/秒?我们ThreadPool.GetAvailableThreads()
每 5 秒记录一次,它表明整个过程中有数千个可用线程。
这段代码大部分时间都运行良好(足够),但是当它失败时,它似乎从程序开始到结束都失败了,大约一个小时左右,当内存耗尽queueA
并且它的项目。所以看起来程序可以进入某种无法恢复的时髦状态。
这是一张每秒处理的物品数量的图表,对于好机器和坏机器,横轴是时间轴。(请注意纵轴是对数)
图表显示,例如,“坏”服务器的上限在大多数情况下约为 17/18 项/秒,而“好”服务器能够执行 3700 项/秒,具体取决于新项目的速率收到并进入queueA
。
由于我对任务库的复杂性不太熟悉,我想知道在某些随机情况下PreferFairness
,异步(因此不是真的)“递归”调用的组合BeginReceive
是否会导致这个问题。还有其他想法如何解决这个问题吗?
注意我已经删除了几个try {} catch { error.log(); }
结构来简化它。没有记录错误,所以我相信代码不会引发异常。而且queueA
它不会单调地增长,它有时会缩小一点,所以这个循环似乎是活的,虽然很慢。
解决方案
这是关于该主题的非常好的阅读材料。
当一个 Task 被调度到默认调度器时,调度器会查看当前队列中的 Task 线程是否是一个拥有自己本地队列的 ThreadPool 线程。如果不是,则工作项将排入全局队列。如果是,调度程序还将检查 Task 的 TaskCreationOptions 值是否包含 PreferFairness 标志,默认情况下不启用。如果设置了标志,即使线程确实有自己的本地队列,调度程序仍然会将任务排入全局队列而不是本地队列。以这种方式,该任务将与全局排队的所有其他工作项一起被公平地考虑。
推荐阅读
- python - 从拆分字符串列创建新列
- javascript - JS 模板文字:未定义
- r - 将函数的参数名称转换为字符串
- python - 用 Pandas 中给定组的平均值划分列的有效方法
- ubuntu - 修复 http+non-www 到 https+www 重定向的 NGINX 配置
- java - 如何捕获从 oracle 到 java 的自定义引发的异常
- ios - 如何克服IOS中实时摄像机视图的缓慢问题
- json - Json解析数组中子数组元素的问题
- git - 删除分支上的“x commits behind master”
- symfony - 如何从存储库中请求新数据并克服实体管理器在学说中持续返回同一实体?