即使ThreadPool.GetAvailableThreads()指示丰富,任务是否会受到缓慢调度的影响?

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

我们有一台服务器在生产中运行,它接收数据,放入queueA。另一个线程一次从queueA获取一个项目,处理它并将其放入queueB

实际上镜像了此设置,以便两个镜像服务器在主动 - 主动冗余设置中接收完全相同的数据并以相同方式处理它们。

大约每年一次,其中一个服务器的消息在queueA中大量堆积,而另一个服务器处理相同的数据就好了。

所以问题似乎是从queueA,进程和入队到queueB的代码。除了(完全没必要)使用任务库之外没有太多进展,如下面的精简版和简化版所示。

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) { }循环中执行所有上述操作,不涉及任何Tasks),这种情况可能会使其执行得如此糟糕,以至于循环旋转的性能大多是15次迭代/秒,最大值低于50次迭代/秒?我们每5秒记录一次ThreadPool.GetAvailableThreads(),它表示整个数千个可用线程。

这段代码在大多数情况下都运行良好(足够),但是当它失败时,它似乎从程序开始直到它结束时失败,大约在一小时左右的范围内,当queueA和内存耗尽时它的物品。所以看起来程序可以进入一些无法恢复的时髦状态。

这是每秒处理的项目数量的图表,对于好机器和坏机器,水平轴是时间轴。 (请注意垂直轴是对数的)

enter image description here

该图表显示例如“坏”服务器的上限大约为17/18项/秒,大部分时间,而“好”服务器能够达到3700项/秒,具体取决于收到新项目的速率并输入queueA

由于我不太熟悉任务库的复杂性,我想知道在某些随机情况下,PreferFairnessBeginReceive的异步(因而不是真的)“递归”调用的组合是否可能导致这个问题。任何其他想法如何到达底部?

注:我删除了几个try {} catch { error.log(); }结构来简化它。没有记录错误,所以我相信代码不会抛出异常。并且queueA不会单调增长,它有时会缩小一点,因此循环似乎是活着的,虽然很慢。

c# .net task-parallel-library
1个回答
0
投票

Here是一个非常好的阅读主题。

当任务被调度到默认调度程序时,调度程序会查看正在排队任务的当前线程是否是具有其自己的本地队列的ThreadPool线程。如果不是,则工作项将排队到全局队列。如果是,则调度程序还将检查Task的TaskCreationOptions值是否包含PreferFairness标志,该标志默认情况下不启用。如果设置了该标志,即使该线程确实有自己的本地队列,调度程序仍会将Task排入全局队列而不是本地队列。通过这种方式,该任务将与全局排队的所有其他工作项一起被公平地考虑。

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