Как заставить мою программу C # спать 50 мс?

222

Как мне заставить мою программу на С# спать в течение 50 миллисекунд?

Это может показаться легким вопросом, но у меня есть временный момент нарушения мозгов!

  • 1
    Повторно помечен на VB.NET, так как там тоже работает ответ.
  • 0
    Нет DrFloyd5,; не работает в VB.NET, верно?
Показать ещё 3 комментария
Теги:

9 ответов

266
Лучший ответ
System.Threading.Thread.Sleep(50);

Помните, что выполнение этого в главном потоке графического интерфейса будет блокировать обновление вашего графического интерфейса (он будет чувствовать себя "вялым" )

Просто удалите ;, чтобы он работал на VB.net.

  • 0
    После вызова sleep в методе программа продолжит выполнение в фоновом режиме (без создания нового потока)? Кроме того, если я вызову sleep в новом потоке, продолжит ли основной поток свою работу?
  • 0
    @JayNirgudkar поток, который вызывает Sleep, будет остановлен. Другие темы не затрагиваются.
Показать ещё 1 комментарий
143

В основном есть 3 варианта ожидания (почти) любого языка программирования:

  • Свободное ожидание
    • Выполнение блоков потоков для заданного времени (= не потребляет вычислительную мощность)
    • Обработка заблокированных/ожидающих потоков невозможна.
    • Не так точно
  • Жесткое ожидание (также называемое жесткой петлей)
    • Процессор
    • ОЧЕНЬ занят за весь интервал ожидания (фактически, он обычно потребляет 100% одного времени обработки ядра)
    • Некоторые действия могут выполняться при ожидании
    • Очень точный
  • Комбинация предыдущих 2
    • Он обычно сочетает эффективность обработки 1. и точность + способность делать что-то из 2.

для 1. - Свободное ожидание в С#:

Thread.Sleep(numberOfMilliseconds);

Тем не менее, планировщик потоков Windows делает acccuracy Sleep() равным 15 мс (поэтому Sleep может легко дождаться 20 мс, даже если планируется ждать только 1 мс).

для 2. - Жесткое ожидание на С#:

Stopwatch stopwatch = Stopwatch.StartNew();
while (true)
{
    //some other processing to do possible
    if (stopwatch.ElapsedMilliseconds >= millisecondsToWait)
    {
        break;
    }
}

Мы могли бы также использовать DateTime.Now или другие средства измерения времени, но Stopwatch намного быстрее (и это действительно станет видимым в узком цикле).

для 3. - Комбинация:

Stopwatch stopwatch = Stopwatch.StartNew();
while (true)
{
    //some other processing to do STILL POSSIBLE
    if (stopwatch.ElapsedMilliseconds >= millisecondsToWait)
    {
        break;
    }
    Thread.Sleep(1); //so processor can rest for a while
}

Этот код регулярно блокирует поток для 1 мс (или немного больше, в зависимости от планирования потоков ОС), поэтому процессор не занят за это время блокировки, а код не потребляет 100% мощности процессора. Другая обработка все еще может выполняться между блокировкой (например, обновление пользовательского интерфейса, обработка событий или выполнение взаимодействия/связи).

  • 1
    Таймер также может представлять интерес
54

Вы не можете указать точное время сна в Windows. Для этого вам нужна ОС реального времени. Лучшее, что вы можете сделать, это указать минимальное время сна. Затем это до планировщика, чтобы разбудить ваш поток после этого. И никогда вызывать .Sleep() в потоке графического интерфейса пользователя.

35

Поскольку теперь у вас есть функция async/await, лучший способ спать в течение 50 мс - использовать Task.Delay:

async void foo()
{
    // something
    await Task.Delay(50);
}

Или, если вы настроили таргетинг на .NET 4 (с Async CTP 3 для VS2010 или Microsoft.Bcl.Async), вы должны использовать:

async void foo()
{
    // something
    await TaskEx.Delay(50);
}

Таким образом, вы не будете блокировать поток пользовательского интерфейса.

  • 0
    Можете ли вы response.flush во время этой задержки, если она находится в цикле?
  • 0
    Нет, ты не можешь. Я считаю, что есть версия FlushAsync .
Показать ещё 2 комментария
31

Используйте этот код

using System.Threading;
// ...
Thread.Sleep(50);
14
Thread.Sleep(50);

Поток не будет запланирован для выполнения операционной системой в течение указанного количества времени. Этот метод изменяет состояние потока, чтобы включить WaitSleepJoin.

Этот метод не выполняет стандартную пересылку COM и SendMessage. Если вам нужно спать в потоке с STAThreadAttribute, но вы хотите выполнить стандартную пересылку COM и SendMessage, рассмотрите возможность использования одной из перегрузок метода Join, который задает интервал времени ожидания.

Thread.Join
10
Thread.Sleep
3

Для удобства чтения:

using System.Threading;
Thread.Sleep(TimeSpan.FromMilliseconds(50));
0

Лучшее из обоих миров:

using System.Runtime.InteropServices;

    [DllImport("winmm.dll", EntryPoint = "timeBeginPeriod", SetLastError = true)]
    private static extern uint TimeBeginPeriod(uint uMilliseconds);

    [DllImport("winmm.dll", EntryPoint = "timeEndPeriod", SetLastError = true)]
    private static extern uint TimeEndPeriod(uint uMilliseconds);
    /**
     * Extremely accurate sleep is needed here to maintain performance so system resolution time is increased
     */
    private void accurateSleep(int milliseconds)
    {
        //Increase timer resolution from 20 miliseconds to 1 milisecond
        TimeBeginPeriod(1);
        Stopwatch stopwatch = new Stopwatch();//Makes use of QueryPerformanceCounter WIN32 API
        stopwatch.Start();

        while (stopwatch.ElapsedMilliseconds < milliseconds)
        {
            //So we don't burn cpu cycles
            if ((milliseconds - stopwatch.ElapsedMilliseconds) > 20)
            {
                Thread.Sleep(5);
            }
            else
            {
                Thread.Sleep(1);
            }
        }

        stopwatch.Stop();
        //Set it back to normal.
        TimeEndPeriod(1);
    }

Ещё вопросы

Сообщество Overcoder
Наверх
Меню