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

发布于 2024-10-30 12:06:10 字数 1013 浏览 1 评论 0原文

好的,所以我一直在使用 VB.net 并集思广益,以实现每 60 秒可靠地启动一个线程,而不管前一个线程需要多长时间才能完成它的工作。这是我的问题。给出以下代码:

    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

在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

我对此输出的假设是,每行之间的时间必须恰好为 5000 毫秒加上执行循环其余部分所需的时间,考虑到磁盘 IO 可能导致未知的延迟,该时间可能会有所不同。我的问题是,查看第 10 行和第 11 行并减去,结果相差 4,958 毫秒。所以我的问题是到底发生了什么?当我告诉线程在完成该过程之前休眠 5000 毫秒时,如何才能获得小于 5000 毫秒的差异。我缺少什么?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

只有影子陪我不离不弃 2024-11-06 12:06:10

首先,要了解所有主要操作系统,尤其是具有多任务功能的操作系统,永远无法将计时器降至毫秒级。该架构根本不支持它。

其次,考虑到会有一些延迟,如果底层框架、操作系统和涉及的任何其他内容设置了 5000 毫秒,那么您的代码将永远在 5000 毫秒时触发,并且总是在x毫秒之后。您观察到的情况很可能是操作系统保留了一些关于平均延迟的记录,并相应地调整超时值,以尝试使平均延迟接近 5000 毫秒。

您可以阅读实时操作系统以获取更多信息。

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.

回忆凄美了谁 2024-11-06 12:06:10

实现建议:如果您需要计时精度,而不是线程内的Do/Loop(使用Thread.Sleep),只需使用System.Timers.Timer 类(这与旧的 WinForms 有很大不同“定时器”对象返回在 .NET 出现之前)。这将允许您指定方法调用之间的TimeSpan

尽管如此,我不能保证 Thread.Sleep 与 Timer 实例之间的真正“精度”(我只是假设 Timer 是更准确,因为计时是其主要功能)...但也许有人可以编写一个快速测试?

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?

知你几分 2024-11-06 12:06:10

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

Maybe your system clock was updated in the middle of the loop.

两仪 2024-11-06 12:06:10

您还必须考虑实例化、打开和创建所需的时间。关闭一个新的 StreamWriter。如果您在循环之外执行此操作,结果将更接近您的预期。

例如:

  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)

产生以下输出:

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

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
聽兲甴掵 2024-11-06 12:06:10

您的难题的答案实际上非常简单。不保证两个语句将在同一时间片中执行。因为在一个语句中有多个调用,所以情况更糟。

您对 DateTime.Now 和 DateTime.Now.Millisecond 的调用很可能会相隔近一秒(特别是如果中间正在进行一些垃圾收集)。

我并不是说这是你的问题,但正如所写,这种可能性是存在的。您可以通过捕获变量中的时间来避免这种可能性。

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

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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文