VB.net Нестабильный Таймер Сна Резьбы - PullRequest
2 голосов
/ 06 апреля 2011

Хорошо, поэтому я играл с 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 миллисекунд плюс время, необходимое для выполнения остальной части цикла, которое может варьироваться, учитывая, что может быть неизвестная задержка из-за дискового ввода-вывода , Моя проблема в том, что просмотр строк 10 и 11 и вычитание дает мне разницу в 4958 миллисекунд. Итак, мой вопрос, что, черт возьми, там происходит? Как можно получить разницу менее 5000 миллисекунд, когда я сказал потоку спать в течение 5000 миллисекунд до завершения процесса. Чего мне не хватает?

Ответы [ 5 ]

3 голосов
/ 06 апреля 2011

Во-первых, следует понимать, что все основные операционные системы, особенно те, которые поддерживают многозадачность, никогда не смогут сбрасывать таймеры до миллисекунды. Архитектура просто не поддерживает это.

Во-вторых, имея в виду, что будет некоторая задержка, если базовые платформы, операционная система и все остальное будет установлено в 5000 миллисекунд, и ваш код никогда не сработает при 5000 миллисекунды и всегда несколько х число миллисекунд после. Скорее всего, вы наблюдаете, как операционная система ведет некоторую запись о средней задержке и соответствующим образом корректирует значение времени ожидания, пытаясь приблизиться к 5000 миллисекундам в среднем.

Вы можете прочитать о операционных системах реального времени , чтобы получить больше информации.

1 голос
/ 06 апреля 2011

Предложение по реализации: Если вам нужна точность синхронизации, вместо Do / Loop внутри потока (с Thread.Sleep), просто используйте экземпляр класса System.Timers.Timer (это очень отличаетсяиз старого объекта WinForms «Таймер» еще в до .NET дней).Это позволит вам указать TimeSpan между вызовами методов.

Хотя я не могу ручаться за истинную "точность" между Thread.Sleep против Timer экземпляра (я только предположил, что Timerбыло бы более точным, учитывая, что хронометраж является его основной функцией) ... но, возможно, кто-то мог бы написать быстрый тест?

0 голосов
/ 06 апреля 2011

Ответ на вашу загадку довольно прост. Нет гарантии, что два оператора будут выполняться в одном и том же временном интервале. Поскольку в одном операторе несколько вызовов, это еще хуже.

Вполне возможно, что ваш вызов DateTime.Now и DateTime.Now.Millisecond может происходить с интервалом почти в секунду (особенно если между ними происходит сборка мусора).

Я не говорю, что это ваша проблема, но, как написано, такая возможность существует. Вы можете избежать этой возможности, фиксируя время в переменной.

Dim dt as DateTime
dt = DateTime.Now
objWriter.Write(intTemp & " " & dt & " " & dt.Millisecond & vbCrLf)
0 голосов
/ 06 апреля 2011

Возможно, ваши системные часы были обновлены в середине цикла.

0 голосов
/ 06 апреля 2011

Вы также должны учитывать время, необходимое для создания экземпляра, открытия и закрытия нового 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
...