Як змусити мою програму C # спати протягом 50 мс?


272

Як змусити мою програму C # спати протягом 50 мілісекунд?

Це може здатися легким питанням, але у мене є момент тимчасової недостатності мозку!


1
Позначивши тег на VB.NET, оскільки там також працює відповідь.
DrFloyd5

Ні DrFloyd5,; не працює на VB.NET, правда?
Заноні

16
Якби я був у команді VB.Net, я б додав; як персонаж коментаря до наступної версії мови ...
Joel Coehoorn

4
Я думаю, що програмісти VB досить яскраві, щоб визначити еквівалент ..
BlueRaja - Danny Pflughoeft

ну, щоб переконатися, тепер вони цього не повинні.
PsychoData

Відповіді:


330
System.Threading.Thread.Sleep(50);

Пам'ятайте, що якщо це зробити в основному потоці графічного інтерфейсу, блокує оновлення вашого графічного інтерфейсу (він буде відчувати себе "млявим")

Просто видаліть, ;щоб він працював і для VB.net.


Після виклику сну методом, чи продовжить програма виконуватись у фоновому режимі (без створення нової теми)? Крім того, якщо я зателефоную сну в новій нитці, чи продовжить основний потік свою роботу?
Джей Ніргудкар

@JayNirgudkar нитка, яка викликає сплячий режим, буде зупинена. Інші теми не зачіпаються.
Ісак Саво

Це не гарантовано є точним.
Акумабурн

150

В основному є 3 варіанти очікування (майже) будь-якої мови програмування:

  1. Повільне очікування
    • Виконання блоків потоків за заданий час (= не споживає обробну потужність)
    • Жодна обробка неможлива для заблокованого / очікуваного потоку
    • Не так точно
  2. Тісне очікування (також його називають щільним циклом)
    • процесор ДУЖЕ зайнятий протягом усього інтервалу очікування (адже він зазвичай споживає 100% часу обробки одного ядра)
    • Деякі дії можна виконувати під час очікування
    • Дуже точно
  3. Поєднання попередніх 2
    • Зазвичай він поєднує ефективність обробки 1. і точність + здатність робити щось 2.

для 1. - Вільне очікування в C #:

Thread.Sleep(numberOfMilliseconds);

Однак планувальник потоків Windows спричиняє накопичення Sleep()близько 15 мс (тому сон може легко чекати 20 мс, навіть якщо планується чекати лише 1 мс).

для 2. - Тісне очікування в C # - це:

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
Таймер також може бути цікавим
JonnyRaa

55

Ви не можете вказати точний час сну в Windows. Для цього вам потрібна ОС у режимі реального часу. Найкраще, що ви можете зробити, це вказати мінімальний час сну. Тоді до планувальника варто прокинути свою нитку після цього. І ніколи не дзвоніть .Sleep()на нитку GUI.


44

Оскільки тепер у вас є функція асинхронізації / очікування, найкращий спосіб спати протягом 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);
}

Таким чином, ви не будете блокувати потік інтерфейсу користувача.


чи можете ви відповісти.flush під час цієї затримки, якщо вона знаходиться в циклі?
Теоман шипахі

Ні, ви не можете. Я вважаю, що є FlushAsyncверсія.
Тоні Петрина

6
Альтернатива, яка не потребує asyncдекларації, - зателефонуватиTask.Delay(50).Wait();
stuartd


14
Thread.Sleep(50);

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

Цей метод не виконує стандартних перекачування COM та SendMessage. Якщо вам потрібно спати на потоці, у якому є STAThreadAttribute, але ви хочете виконати стандартну перекачку COM і SendMessage, подумайте про використання одного з перевантажень методу Join, який визначає інтервал очікування.

Thread.Join


0

Починаючи з .NET Framework 4.5, ви можете використовувати:

using System.Threading.Tasks;

Task.Delay(50).Wait();   // wait 50ms

-1

Кращі з обох світів:

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);
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.