Thread.Sleep менее 1 миллисекунды - PullRequest
28 голосов
/ 06 июня 2011

Я хочу вызвать спящий поток менее чем за 1 миллисекунду. Я читал, что ни нить. Сон, ни ОС Windows не поддерживают это.

какое решение для этого?

Для всех, кому интересно, зачем мне это нужно: Я делаю стресс-тест и хочу узнать, сколько сообщений мой модуль может обрабатывать в секунду. Итак, мой код:

 // Set the relative part of Second hat will be allocated for each message 
 //For example: 5 messages - every message will get 200 miliseconds 
 var quantum = 1000 / numOfMessages;

 for (var i = 0; i < numOfMessages; i++)
 {
      _bus.Publish(new MyMessage());
      if (rate != 0) 
          Thread.Sleep(quantum);
 }

Я буду рад узнать ваше мнение по этому поводу.

Ответы [ 6 ]

41 голосов
/ 06 июня 2011

Вы не можете сделать это. Один неактивный вызов обычно блокируется гораздо дольше миллисекунды (это зависит от операционной системы и системы, но по моему опыту Thread.Sleep(1) имеет тенденцию блокироваться где-то между 12-15 мс).

Windows, как правило, не предназначена для операционной системы реального времени . Этот тип управления, как правило, невозможно достичь в обычных (настольных / серверных) версиях Windows.

Самое близкое, что вы можете получить, - это, как правило, вращать и использовать циклы ЦП, пока вы не достигнете желаемого времени ожидания (измерено с помощью высокопроизводительного счетчика). Это, однако, довольно ужасно - вы израсходуете весь процессор, и даже тогда вы, вероятно, время от времени будете получать прерванный операционной системой и эффективно "спать" дольше 1 мс ...

19 голосов
/ 06 марта 2014

Код ниже определенно предложит более точный способ блокировки, вместо вызова Thread.Sleep(x); (хотя этот метод блокирует поток, не переводит его в sleep ),Ниже мы используем класс StopWatch, чтобы измерить, как долго нам нужно продолжать цикл и блокировать вызывающий поток.

using System.Diagnostics;

private static void NOP(double durationSeconds)
{
    var durationTicks = Math.Round(durationSeconds * Stopwatch.Frequency);
    var sw = Stopwatch.StartNew();

    while (sw.ElapsedTicks < durationTicks)
    {

    }
}

Пример использования,

private static void Main()
{
    NOP(5); // Wait 5 seconds.

    Console.WriteLine("Hello World!");

    Console.ReadLine();
}
10 голосов
/ 07 июня 2011

Почему? Обычно на одном компьютере имеется очень ограниченное количество процессоров и ядер - вы получаете лишь небольшое количество, если независимые исполнительные блоки.

С другой стороны, существует ряд процессов и много других потоков.Каждый поток требует некоторого процессорного времени, которое назначается внутренне процессами ядра Windows.Обычно Windows блокирует все потоки и выделяет определенное количество времени ядра процессора определенным потокам, затем переключает контекст на другие потоки.

Когда вы вызываете Thread.Sleep, независимо от того, насколько маленьким вы убиваете весь промежуток времени Windowsдал потоку, поскольку нет никакой причины просто ждать это, и контекст переключается немедленно.Это может занять несколько мс, когда Windows в следующий раз предоставит вашему процессору немного процессора.

Что использовать? В качестве альтернативы, вы можете вращать ваш процессор , вращение - не страшная вещь и может быть очень полезным.Например, он используется в пространстве имен System.Collections.Concurrent с неблокирующими коллекциями, например:

SpinWait sw = new SpinWait();
sw.SpinOnce();
6 голосов
/ 06 июня 2011

Большинство законных причин для использования Thread.Sleep(1) или Thread.Sleep(0) связаны с довольно продвинутыми методами синхронизации потоков. Как и Рид сказал , вы не получите желаемого разрешения, используя обычные методы. Я не знаю наверняка, что вы пытаетесь достичь, но я могу предположить, что вы хотите, чтобы действие происходило с интервалом в 1 миллисекунду. Если это так, взгляните на мультимедийные таймеры . Они могут обеспечить разрешение до 1 мс. К сожалению, в .NET Framework (который я знаю) нет встроенного API, который бы использовал эту функцию Windows. Но вы можете использовать уровень взаимодействия для вызова непосредственно в Win32 API. Есть даже примеры сделать это в C #.

4 голосов
/ 06 июня 2011

В старые добрые времена вы использовали API-интерфейс QueryPerformanceTimer в Win32, когда требовалось разрешение менее милисекунды.

Кажется, есть больше информации по этому вопросу в Code-Project: http://www.codeproject.com/KB/cs/highperformancetimercshar.aspx

Это не позволит вам "Sleep ()" с тем же разрешением, на которое указал Рид Копси.

Edit: Как отмечают Рид Копси и Брайан Гидеон, QueryPerfomanceTimer был заменен на Stopwatch в .NET

0 голосов
/ 03 октября 2018

По моему опыту это похоже на отсутствие сна

Thread.Sleep(1/3) 

Я не проверял точное время в мс, отведенное для сна, но это ответ на то, что я искал, когда достиг этой темы. Так что, возможно, это поможет кому-то еще. Если быть точным, я искал время сна менее 1 мс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...