0

我说明我的情况。

我有一个生产者 1 对 N 消费者模式。我正在使用阻塞集合,一切都运行良好。做一些测试我注意到这种奇怪的行为:

我正在测试我对数据的操作在我的消费者中花费了多长时间。我注意到了这个奇怪的事情,在下面你会发现我的操作清除了代码并产生了奇怪的行为。

我有 1 个生产者的 4 个消费者。对于大多数数据,控制台不打印任何内容,因为 ts=0(它在一个刻度下)但随机(每 1 到 5 秒之间)它会绘制类似这样的东西(不是按这个非常特定的顺序,而是同一种):

10000
20001
10000
30002
10000
40003
10000
10000

它大约是 10,000 个滴答声,因此大约需要 1 毫秒。总是格式为 (N)000(N-1) 的数字 请注意,我使用的 BlockingCollection 是根据完全随机发生的一些网络事件填充的。从这里没有什么规律的。

时机几乎是完美的,总是 10,000 滴答声的倍数。

这背后可能是什么?谢谢!

    while(IsAlive)
    {
            DataToFieldMapping item;
            try
            {
                _CollectionToConsume.TryTake(out item, -1);
            }
            catch
            {
                item = null;
            }
            if (item != null)
            {
                    long ts = (DateTime.Now.Ticks - item.TimeStamp.Ticks);
                    if(ts>10)
                       Console.WriteLine(ts);
            }
     }
4

2 回答 2

4

这里发生的情况是DateTime.Now精度相当有限。它没有给你时间到最近的滴答声。它仅每 10,000 次左右更新一次,这就是为什么您通常会在打印中看到 10,000 次的倍数。

如果您真的想更好地了解这些事件的持续时间,请使用精度更高StopWatch类。也就是说,它只是一个诊断工具(因此它位于名称空间中)。您应该只使用它来帮助您诊断正在发生的事情,并且应该在生产代码中使用它。StopWatchDiagnostics

附带说明一下,这里根本不需要使用计时器。您似乎正在创建几个正在轮询BlockingCollection新内容的消费者。没有理由这样做。他们可以简单地阻塞,直到集合有项目。(因此得名,BlockingCollection.

最简单的方法是让消费者简单地这样做:

foreach(var item in _CollectionToConsume.GetConsumingEnumerable())
   ProcessItem(item);

然后只需在后台线程中运行该代码。

于 2014-03-07T19:28:52.980 回答
1

如果您编写以下内容并运行,您会看到刻度不会一对一滚动,而是在相对较大的块中 b/c 刻度分辨率实际上要小得多。

for(int i =0; i< 100; i++)
{
    Console.WriteLine(DateTime.Now.Ticks);
}

使用Stopwatch类来衡量性能,因为该类使用更适合该目的的高分辨率计时器。

于 2014-03-07T19:31:13.257 回答