简体   繁体   English

线程和计时器的奇怪行为

[英]Strange Behavior with Threading and Timer

I explain my situation. 我解释我的情况。

I have a producer 1 to N consumers pattern. 我有一个生产者1到N的消费者模式。 I'm using blocking collections and everything is working well. 我正在使用阻止收集,并且一切正常。 Doing some test I noticed this strange behavior: 做一些测试,我注意到了这种奇怪的行为:

I was testing how long my manipulation of data took in my consumers. 我正在测试对数据的处理花费了我的消费者多长时间。 I noticed this strange things, below you'll find the code cleaned of my manipulation and which produce the strange behavior. 我注意到了这些奇怪的事情,在下面您会发现清除了我的操作的代码,这些代码会产生奇怪的行为。

I have 4 consumers for 1 producer. 我有1个生产者的4个消费者。 For most of data, the Console doesn't print anything, because ts=0 (its under a tick) but randomly (between every 1 to 5sec) it plots something like this (not in this very specific order, but of the same kind): 对于大多数数据,控制台不打印任何内容,因为ts = 0(在刻度线下),但是随机(每1至5秒之间),它会绘制类似这样的内容(不是以这种非常特定的顺序,而是相同的种类) ):

10000
20001
10000
30002
10000
40003
10000
10000

It is of the order of 10,000 ticks so around 1ms. 它大约是10,000个滴答声,所以大约1毫秒。 Always a number in the format (N)000(N-1) Note that the BlockingCollection I consume is filled depending on some network events which occurred completely at random times. 始终为(N)000(N-1)格式的数字。请注意,我消耗的BlockingCollection是根据完全随机发生的某些网络事件填充的。 Nothing regular from here. 这里没有常规。

The timing is almost perfect, always a multiple of 10,000 ticks. 时机几乎是完美的,总是10,000刻度的倍数。

What could be behind this ? 这可能是什么呢? Thks ! ks!

    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);
            }
     }

What's going on here is that DateTime.Now has a fairly limited precision. 这里发生的是DateTime.Now精度相当有限。 It's not giving you the time to the nearest tick. 它没有给您时间到最近的滴答声。 It is only updated every 10,000 ticks or so, which is why you generally see multiples of 10k ticks in your prints. 它仅每10,000个刻度左右才更新一次,这就是为什么您通常在打印物中看到1万个刻度的倍数的原因。

If you really want to get a better feel for the duration of those events, use the StopWatch class, which has a much higher precision. 如果你真的想获得这些事件的持续时间更好的手感,使用StopWatch类,它具有更高的精度。 That said, StopWatch is simply a diagnostic tool (hence why it's in the Diagnostics namespace). 就是说, StopWatch只是一个诊断工具(因此,它为什么位于Diagnostics名称空间中)。 You should only be using it to help you diagnose what's going on, and should be using it in production code. 您应该仅使用它来帮助您诊断正在发生的事情,并且应该在生产代码中使用它。

On a side note, there really isn't any need to use a timer here at all. 顺便说一句,这里实际上根本不需要使用计时器。 It appears that you're creating several consumers that are polling the BlockingCollection for new content. 看来您正在创建几个使用方,它们正在BlockingCollection中轮询新内容。 There is no reason to do this. 没有理由这样做。 They can simply block until the collection has items. 他们可以简单地阻止,直到集合中有项目为止。 (Hence the name, BlockingCollection . (因此,名称为BlockingCollection

The easiest way is for the consumers to simply do this: 最简单的方法是让消费者简单地做到这一点:

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

Then just run that code in a background thread. 然后,只需在后台线程中运行该代码即可。

if you write the following and run, you'll see that ticks do not roll one to one, but rather in relatively large chunks b/c ticks resolution is actually much smaller. 如果编写以下代码并运行,您会发现刻度不会一一对应,而在相对较大的块中,b / c刻度的分辨率实际上要小得多。

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

Use Stopwatch class to measure performance as that one uses a high-resolution timer which is much more suitable for the purpose. 使用Stopwatch类来衡量性能,因为它使用了更适合此目的的高分辨率计时器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM