【问题标题】:Why is this code executing faster than expected?为什么这段代码的执行速度比预期的要快?
【发布时间】:2009-04-03 14:49:20
【问题描述】:

我有这个代码:

    public void replay() {
        long previous = DateTime.Now.Ticks;
        for (int i = 0; i < 1000; i++) {
            Thread.Sleep(300);
            long cur = DateTime.Now.Ticks;
            Console.WriteLine(cur - previous);
            previous = cur;
        }
    }

像这样作为单独的线程调用:

        MethodInvoker replayer = new MethodInvoker(replay);
        replayer.BeginInvoke(null, null);

但是,如果我查看输出,它的行为会很奇怪。它成对输出i。例如,它会等待一个完整的等待,然后输出i,然后也快速输出下一个i,然后再次等待。为什么会这样,我该如何纠正?

它输出这个:

3125040
2968788
2968788
2968788
3125040
2968788
2968788
2968788
3125040
2968788
2968788
2968788
3125040

如果我将睡眠时间增加到一秒以上,这不会发生。

【问题讨论】:

  • 首先,这是发布模式还是调试模式?其次,使用计时器而不是仅仅观看控制台输出 - 不能保证控制台会立即显示内容。
  • 你确定这不是在控制台缓冲吗?
  • 查看输出,小于 5 % 的差异是循环执行之间的延迟......感知到的差异只是在显示中......

标签: c# .net multithreading execution


【解决方案1】:

更改代码以消除分析中的显示延迟:

public void replay() 
{        
    Thread.Sleep(5000);
    DateTime start = DateTime.Now;      
    for (int i = 0; i < 1000; i++) 
    {            
          Console.WriteLine(string.Format("Exec:{0} - {1} ms",
                i, DateTime.Now - start));
          start = DateTime.Now;
          Thread.Sleep(300);        
    }
}

查看您修改后的输出,循环延迟的方差不到 5%(300 个中的 15 毫秒)。这是正常的,因为操作系统实际将时间片分配给线程时所涉及的不确定性......(如果我没记错的话,在 Windows 操作系统中,这通常是每 20 毫秒!)

您在控制台输出中看到的较大差异几乎可以肯定是由于显示延迟。

【讨论】:

    【解决方案2】:

    无法复制。我想知道它是否是您机器本地的东西;缓冲,也许吧。

    【讨论】:

    • 同上。调出任务管理器并查看您的流程。我怀疑有些东西正在消耗周期。
    • 建议 OP 将输出写入其他内容 - 也许是 Dictionary - 仔细检查
    • 更新了问题以显示更多数据。我在四核上,大部分 CPU 都没有使用。
    • 阅读这个问题你就知道了。问题是它睡得不均匀。
    • 但是每个输出只有大约 300 毫秒,不是吗?
    【解决方案3】:

    我无法重现此内容,但您可能需要考虑使用计时器。它会更可靠。

    public class Counter
    {
        private readonly TimeSpan initialDelay, incrementDelay;
        private readonly int maxCount;
        private Timer timer;
        private int count;
    
        public Counter(TimeSpan initialDelay, TimeSpan incrementDelay, int maxCount)
        {
            this.maxCount = maxCount;
            this.initialDelay = initialDelay;
            this.incrementDelay = incrementDelay;
        }
    
        public void Start(Action<int> tickBehavior)
        {
            if (timer != null)
            {
                Timer temp = timer;
                timer = null;
                temp.Dispose();
            }
            timer = new Timer(() =>
                {
                    tickBehavior(count++);
                    if (count > maxCount) timer.Dispose();
                }, null, initialDelay, incrementDelay);
        }
    }
    

    使用它:

    Counter counter = new Counter(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(.3), 1000);
    counter.Start((count) => Console.WriteLine(count););
    

    编辑

    我正在使用System.Threading.Timer,但Counter 可以根据您的需要轻松修改为使用System.Timers.TimerSystem.Windows.Forms.Timer。请参阅this link for a description 了解何时使用哪些计时器。

    【讨论】:

    • +1 那段代码是我整个星期见过的最酷的东西 :)
    【解决方案4】:

    您在循环中的睡眠时间只有 300 毫秒,这不是很长。您的应用程序将执行以下操作:

    • 睡眠 5 秒
    • 打印 0
    • 睡眠 300 毫秒
    • 打印 1
    • 睡眠 300 毫秒
    • 打印 2

    等等

    【讨论】:

    • 但事实并非如此,这就是问题所在。
    猜你喜欢
    • 2022-01-19
    • 2017-11-04
    • 1970-01-01
    • 1970-01-01
    • 2013-06-26
    • 1970-01-01
    • 2020-05-14
    • 2016-01-23
    相关资源
    最近更新 更多