问题
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. 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.
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. My problem is that looking at lines 10 and 11 and subtracting gives me a difference of 4,958 milliseconds. 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. What am I missing?
回答1:
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). This will let you specify a TimeSpan
between method calls.
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?
回答2:
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. 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.
You can read about real time operating systems to get more information.
回答3:
Maybe your system clock was updated in the middle of the loop.
回答4:
You also have to consider the time that it takes to instantiate, open & close a new 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
回答5:
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).
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)
来源:https://stackoverflow.com/questions/5557817/vb-net-inconsistant-thread-sleep-timer