简体   繁体   English

VB.net不一致的线程睡眠计时器

[英]VB.net Inconsistant Thread Sleep Timer

Ok so I have been playing with VB.net and brainstorming ways to accomplish launching a thread reliably every 60 seconds reguardless of how long the prior thread took to do it's work. 好的,所以我一直在使用VB.net并进行集思广益,以确保每60秒可靠地启动一个线程,而不必考虑先前线程花费了多长时间来完成工作。 Here is my question. 这是我的问题。 Given the following code: 给出以下代码:

    Dim intTemp As Integer
    intTemp = 2
    Do While intTemp > 1
        Dim objWriter As New System.IO.StreamWriter("C:\Documents\Visual Studio 2010\Projects\Report\Report\Stream.txt", True)
        intTemp = intTemp + 1
        System.Threading.Thread.Sleep(5000)

        objWriter.Write(intTemp & " " & Date.Now & " " & Date.Now.Millisecond & vbCrLf)
        objWriter.Close()
    Loop

Produces this in the stream.txt file. 在stream.txt文件中生成此文件。

3 4/5/2011 9:41:27 AM 807
4 4/5/2011 9:41:32 AM 812
5 4/5/2011 9:41:37 AM 817
6 4/5/2011 9:41:42 AM 822
7 4/5/2011 9:41:47 AM 826
8 4/5/2011 9:41:52 AM 831
9 4/5/2011 9:41:57 AM 836
10 4/5/2011 9:42:02 AM 841
11 4/5/2011 9:42:07 AM 799

My assumption for this output would be that the time between each line would have to be exactly 5000 milliseconds plus the time it takes to execute the rest of the loop which could vary given that there could be an unknown delay due to disk IO. 我对此输出的假设是,每行之间的时间必须恰好是5000毫秒加上执行其余循环所需的时间,这可能会有所变化,因为磁盘IO可能会导致未知的延迟。 My problem is that looking at lines 10 and 11 and subtracting gives me a difference of 4,958 milliseconds. 我的问题是看10和11行并减去后得出的差值为4958毫秒。 So my question is what the heck is going on there? 所以我的问题是到底发生了什么? How is it possible to get a difference of less than 5000 milliseconds when I have told the thread to sleep for 5000 milliseconds before completing the process. 当我告诉线程在完成该过程之前要睡眠5000毫秒时,如何才能获得小于5000毫秒的时间差。 What am I missing? 我想念什么?

First, understand that all major operating systems, especially those with multitasking capabilities will never be capable of landing timers down to the millisecond. 首先,要了解所有主要操作系统,尤其是那些具有多任务处理能力的操作系统,永远都无法将计时器降到毫秒以下。 The architecture simply doesn't support it. 该体系结构根本不支持它。

Second, with the idea in mind that there will be some delay, if a setting of 5000 milliseconds were set by the underlying frameworks, operating system and whatever else is involved your code would never fire at 5000 milliseconds and always some x number of milliseconds after. 其次,考虑到会有一些延迟,如果基础框架,操作系统和其他涉及的内容设置了5000毫秒的设置,则您的代码将永远不会在5000毫秒后触发,并且在之后总是x毫秒数。 What you're observing is most likely the operating system keeping some record as to the average delay and adjusting the timeout value accordingly in an attempt to land closer to 5000 milliseconds on average. 您正在观察的操作系统很可能会保留一些有关平均延迟的记录,并相应地调整超时值,以尝试平均降落到接近5000毫秒。

You can read about real time operating systems to get more information. 您可以阅读有关实时操作系统的信息,以获取更多信息。

Implementation Suggestion: If you need timing precision, instead of a Do/Loop inside of a thread (with Thread.Sleep ), just use an instance of the System.Timers.Timer class (this is very different from the old WinForms "Timer" object back in pre-.NET days). 实施建议:如果需要计时精度,而不是使用线程内部的Do / Loop(使用Thread.Sleep ),只需使用System.Timers.Timer类的实例即可(这与旧的WinForms“ Timer”有很大的不同) .NET之前的天数)。 This will let you specify a TimeSpan between method calls. 这将使您可以指定方法调用之间的时间TimeSpan

Although, I can't vouch for true "precision" between Thread.Sleep vs. a Timer instance (I just assumed a Timer would be more accurate, given that Timekeeping is its primary function)... but perhaps someone could write up a quick test? 虽然,我不能保证Thread.SleepTimer实例之间的真正“精确度”(我只是假设Timer会更精确,因为Timekeeper是其主要功能)...但是也许有人可以写出一个快速测试?

You also have to consider the time that it takes to instantiate, open & close a new StreamWriter. 您还必须考虑实例化,打开和关闭新的StreamWriter所花费的时间。 If you do this outside of the loop the results will be much closer to what you expect. 如果您在循环之外执行此操作,则结果将更接近您的预期。

For example: 例如:

  Dim builder As New Text.StringBuilder()
  For i As Integer = 0 To 10
    Threading.Thread.Sleep(1000)
    builder.AppendLine(String.Format("{0} {1} {2}", i, Now, Now.Millisecond))
  Next
  IO.File.WriteAllText("c:\sleepTest.txt", builder.ToString)

Produces this output: 产生以下输出:

0 4/5/2011 3:15:35 PM 974
1 4/5/2011 3:15:36 PM 988
2 4/5/2011 3:15:37 PM 988
3 4/5/2011 3:15:38 PM 988
4 4/5/2011 3:15:39 PM 989
5 4/5/2011 3:15:40 PM 989
6 4/5/2011 3:15:41 PM 989
7 4/5/2011 3:15:42 PM 989
8 4/5/2011 3:15:43 PM 989
9 4/5/2011 3:15:44 PM 989
10 4/5/2011 3:15:45 PM 989

也许您的系统时钟在循环的中间进行了更新。

The answer to your connundrum is pretty simple really. 难题的答案确实很简单。 There is no guarantee that two statements will execute in the same time slice. 不能保证两个语句将在同一时间段内执行。 Because you have multiple calls in a single statement, it's even worse. 因为您在一个语句中有多个调用,所以情况更糟。

It's quite possible that your call to DateTime.Now and DateTime.Now.Millisecond could occur nearly a second apart (particularly if some garbage collection were going on in between). 您对DateTime.Now和DateTime.Now.Millisecond的调用很可能相隔将近一秒钟(尤其是在之间进行一些垃圾收集时)。

I'm not saying that IS your problem, but as written that possibility exists. 我并不是说这是您的问题,但按照书面记载,这种可能性存在。 You can avoid that possibility by capturing the time in a variable. 您可以通过在变量中捕获时间来避免这种可能性。

Dim dt as DateTime
dt = DateTime.Now
objWriter.Write(intTemp & " " & dt & " " & dt.Millisecond & vbCrLf)

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

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