为什么这段代码执行速度比预期的要快?

时间:2021-06-16 20:20:01

I have this code:

我有这个代码:

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

Which is invoked as a separate thread like this:

这被调用为一个单独的线程,如下所示:

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

However, if I watch the output, it acts strangely. It outputs i in pairs. For example, it'll wait a full wait, then output i, then quickly output the next i too, then wait again. Why is it doing that and how can I correct it?

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

It outputs this:

它输出:

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

If I increase the sleep to more than a second this doesn't happen.

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

4 个解决方案

#1


Change the code to eliminate display latency in your analysis:

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

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

Looking at your modified output, there is less than 5% variance (15ms out of the 300) in the loop delay. This is normal, due to the uncertainties involved in when the OS actually assigns timeslices to the thread... (If I recall correctly, in a windows OS, this is normally only every 20 ms !)

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

The larger discrepancy you perceive in the console output is almost certainly due to display latencys.

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

#2


Cannot reproduce. I wonder if it is something local to your machine; buffering, perhaps.

无法重现。我想知道它是否适用于您的机器;也许是缓冲。

#3


I can't reproduce this, but you might want to consider a timer. It would be more reliable.

我无法重现这一点,但你可能想要考虑一个计时器。它会更可靠。

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

Use it:

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

EDIT

I'm using System.Threading.Timer, but Counter could be easily be modified to use System.Timers.Timer or System.Windows.Forms.Timer depending on your need. See this link for a description of when to use which timers.

我正在使用System.Threading.Timer,但可以很容易地修改Counter以使用System.Timers.Timer或System.Windows.Forms.Timer,具体取决于您的需要。有关何时使用哪些计时器的说明,请参阅此链接。

#4


Your sleep inside the loop is only 300ms, which isn't very long. You application will do the following:

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

  • Sleep 5 secs
  • 睡5秒

  • print 0
  • Sleep 300ms
  • print 1
  • Sleep 300ms
  • print 2

etc.

#1


Change the code to eliminate display latency in your analysis:

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

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

Looking at your modified output, there is less than 5% variance (15ms out of the 300) in the loop delay. This is normal, due to the uncertainties involved in when the OS actually assigns timeslices to the thread... (If I recall correctly, in a windows OS, this is normally only every 20 ms !)

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

The larger discrepancy you perceive in the console output is almost certainly due to display latencys.

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

#2


Cannot reproduce. I wonder if it is something local to your machine; buffering, perhaps.

无法重现。我想知道它是否适用于您的机器;也许是缓冲。

#3


I can't reproduce this, but you might want to consider a timer. It would be more reliable.

我无法重现这一点,但你可能想要考虑一个计时器。它会更可靠。

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

Use it:

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

EDIT

I'm using System.Threading.Timer, but Counter could be easily be modified to use System.Timers.Timer or System.Windows.Forms.Timer depending on your need. See this link for a description of when to use which timers.

我正在使用System.Threading.Timer,但可以很容易地修改Counter以使用System.Timers.Timer或System.Windows.Forms.Timer,具体取决于您的需要。有关何时使用哪些计时器的说明,请参阅此链接。

#4


Your sleep inside the loop is only 300ms, which isn't very long. You application will do the following:

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

  • Sleep 5 secs
  • 睡5秒

  • print 0
  • Sleep 300ms
  • print 1
  • Sleep 300ms
  • print 2

etc.