Jak sprawić, aby mój program C # spał przez 50 ms?


272

Jak sprawić, aby mój program C # spał przez 50 milisekund?

To może wydawać się łatwe pytanie, ale mam chwilową chwilę niewydolności mózgu!


1
Ponownie otagowano na VB.NET, ponieważ odpowiedź tam również działa.
DrFloyd5,

Nie DrFloyd5; nie działa na VB.NET, prawda?
Zanoni,

16
Gdybym był w zespole VB.Net, dodałbym; jako znak komentarza do następnej wersji języka ...
Joel Coehoorn

4
Myślę, że programiści VB są wystarczająco
bystrzy

cóż, dla pewności, teraz nie muszą.
PsychoData,

Odpowiedzi:


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

Pamiętaj jednak, że wykonanie tego w głównym wątku GUI zablokuje aktualizację GUI (będzie się wydawać „powolne”)

Wystarczy usunąć, ;aby działało to również dla VB.net.


Czy po wywołaniu metody sleep w metodzie program będzie nadal działał w tle (bez tworzenia nowego wątku)? Ponadto, jeśli wywołam tryb uśpienia w nowym wątku, czy wątek główny będzie kontynuował pracę?
Jay Nirgudkar

@JayNirgudkar wątek, który wywołuje tryb uśpienia, zostanie zatrzymany. Nie ma to wpływu na inne wątki.
Isak Savo

Nie gwarantuje się, że będzie to dokładne.
Akumaburn,

150

Zasadniczo istnieją 3 opcje czekania w (prawie) dowolnym języku programowania:

  1. Luźne czekanie
    • Wykonywanie bloków wątków dla danego czasu (= nie zużywa mocy obliczeniowej)
    • Przetwarzanie wątku zablokowanego / oczekującego nie jest możliwe
    • Nie tak precyzyjnie
  2. Ciasne oczekiwanie (zwane również ciasną pętlą)
    • procesor jest BARDZO zajęty przez cały okres oczekiwania (w rzeczywistości zwykle zajmuje 100% czasu przetwarzania jednego rdzenia)
    • Niektóre czynności można wykonać podczas oczekiwania
    • Bardzo dokładny
  3. Połączenie poprzednich 2
    • Zwykle łączy wydajność przetwarzania 1. i precyzję + umiejętność zrobienia czegoś 2.

dla 1. - Luźne oczekiwanie w C #:

Thread.Sleep(numberOfMilliseconds);

Jednak harmonogram wątków w systemie Windows powoduje, że dokładność Sleep()wynosi około 15 ms (więc tryb uśpienia może z łatwością czekać 20 ms, nawet jeśli zaplanowano, że czeka tylko 1 ms).

dla 2. - Ciasne oczekiwanie w C # to:

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

Możemy również użyć DateTime.Nowinnych środków pomiaru czasu, ale Stopwatchjest on znacznie szybszy (a to naprawdę stałoby się widoczne w ciasnej pętli).

dla 3. - Połączenie:

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
}

Ten kod regularnie blokuje wątek przez 1ms (lub nieco dłużej, w zależności od planowania wątków systemu operacyjnego), więc procesor nie jest zajęty przez ten czas blokowania i kod nie zużywa 100% mocy procesora. Inne przetwarzanie może być nadal wykonywane pomiędzy blokowaniem (takie jak: aktualizacja interfejsu użytkownika, obsługa zdarzeń lub wykonywanie interakcji / komunikacji).


1
Interesujący może być także licznik czasu
JonnyRaa

55

Nie można określić dokładnego czasu uśpienia w systemie Windows. Potrzebujesz do tego systemu operacyjnego w czasie rzeczywistym. Najlepsze, co możesz zrobić, to określić minimalny czas snu. Następnie program planujący musi obudzić Twój wątek. I nigdy nie wzywaj .Sleep()wątku GUI.


44

Ponieważ teraz masz funkcję asynchronizacji / oczekiwania, najlepszym sposobem na sen przez 50 ms jest użycie Task.Delay:

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

Lub jeśli celujesz w .NET 4 (z Async CTP 3 dla VS2010 lub Microsoft.Bcl.Async), musisz użyć:

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

W ten sposób nie zablokujesz wątku interfejsu użytkownika.


czy potrafisz response.flush podczas tego opóźnienia, jeśli jest w pętli?
Teoman shipahi

Nie, nie możesz. Wierzę, że jest FlushAsyncwersja.
Toni Petrina,

6
Alternatywą, która nie wymaga asyncdeklaracji, jest zadzwonienieTask.Delay(50).Wait();
stuartd


14
Thread.Sleep(50);

Wątek nie będzie planowany do wykonania przez system operacyjny przez określony czas. Ta metoda zmienia stan wątku na WaitSleepJoin.

Ta metoda nie wykonuje standardowego pompowania COM i SendMessage. Jeśli chcesz spać w wątku, który ma STAThreadAttribute, ale chcesz wykonać standardowe pompowanie COM i SendMessage, rozważ użycie jednego z przeciążeń metody Join, która określa limit czasu.

Thread.Join


0

Począwszy od .NET Framework 4.5, możesz użyć:

using System.Threading.Tasks;

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

-1

Najlepsze z obu światów:

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);
    }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.