Насколько точна Thread.Sleep (TimeSpan)?

Я столкнулся с единичным тестом, который прерывается с перерывами, потому что прошедшее время не то, что я ожидаю.

Пример того, как выглядит этот тест:

Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); TimeSpan oneSecond = new TimeSpan(0, 0, 1); for(int i=0; i<3; i++) { Thread.Sleep(oneSecond); } stopwatch.Stop(); Assert.GreaterOrEqual(stopwatch.ElapsedMilliseconds, 2999); 

Большую часть времени это проходит, но он потерпел неудачу, по крайней мере, однажды потерпел неудачу, потому что:

Ожидаемое: больше или равно 2999 Но было: 2998

Я не понимаю, как это может быть меньше 3 секунд. Есть ли проблема с проблемой Thread.Sleep или, возможно, с секундомером, о котором я не знаю?

Как обновление некоторых из приведенных ниже вопросов. Сценарий, который тестируется модулем, является classом, который позволяет вызвать метод для выполнения какого-либо действия, и если он терпит неудачу, подождите второй и вспомните этот метод. Тест, показанный выше, является лишь приближением к тому, что происходит.

Предположим, что я хотел вызвать метод DoSomething () … но в случае исключения из DoSomething (), я хочу, чтобы повторить попытку, вызвав его максимум до 3 раз, но подождите 1 секунду между каждой попыткой. objectiveю единичного теста в этом случае является проверка того, что когда мы запросили 3 повтора с 1 секундой ожидания между каждой попыткой, общее время, затраченное на большее, чем 3 секунды.

    Ваша нить разделяет время процессора с другими streamами. Сон закончится, как только вы вернетесь, и kernel ​​замечает, что время сна истекло, поэтому это не так точно.

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

    Thread.Sleep не предназначен для точного бодрствования. Действительно, сама архитектура окон не предназначена для такого рода вещей.

    Быстро экспериментируя, я замечаю, что fragment кода …

    do {Debug.WriteLine (DateTime.Now.TimeOfDay.TotalMilliseconds.ToString ()); } while (1);

    отображает одно и то же число несколько раз, затем перескакивает на новый номер, отображаемый несколько раз и т. д. Разрыв между этими наборами чисел составляет 15.625мс, который я замечаю, это 1000/64.

    Похоже, что таймеры Windows имеют степень детализации 1/64 секунды. Если вам нужно лучше, чем тогда, я почувствую вашу боль, но это основа, в которой вы должны вписаться. (Windows не является жесткой оперативной ОС и не претендует на это).

    Нить спать и время / дросселирование очень разные вещи, и их следует рассматривать соответствующим образом. Спящий stream – общая задача, позволяющая системе давать другим streamам и процессам возможность выполнить, не будучи конкретными. С другой стороны, регулирование приложения или планирование задач, требующих точного времени, должно выполняться с явным таймером.

    Имейте в виду, если вам нужны точные процессы или синхронизация, вам будет трудно достичь этого с помощью обычного процесса в windowsх. Вам нужно будет использовать приоритеты в реальном времени в Windows, чтобы успешно достичь точного времени или дросселирования, поскольку windows могут спать любой stream в любое время, если он выгружен другим streamом.

    В одном приложении, где я хотел спать по меньшей мере за миллисекунды, я использовал некоторый код, похожий на:

     public void Sleep(int milliseconds) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); while (stopwatch.ElapsedMilliseconds < milliseconds) { int timeout = milliseconds - stopwatch.ElapsedMilliseconds; Thread.Sleep(timeout >= 0 ? timeout : 0); } stopwatch.Stop(); } 

    В ответ на то, насколько точна Thread.Sleep, она не совсем точная. Я думаю, что разрешение составляет около 10 мс. Не гарантируется большая часть чего-либо, кроме «приблизительно» этого долгого времени.

    Может быть, вы не полагаетесь на временную предвзятость, чтобы узнать, успешно ли вы. Лучше подсчитайте количество попыток и оцените это:

     int tries; for(tries=0; tries<3; tries++) { Thread.Sleep(oneSecond); } Assert.GreaterOrEqual(tries, 3); 
    Давайте будем гением компьютера.