Wie kann ich mein C # -Programm für 50 ms in den Ruhezustand versetzen?


272

Wie kann ich mein C # -Programm für 50 Millisekunden in den Ruhezustand versetzen?

Dies mag eine einfache Frage sein, aber ich habe einen vorübergehenden Moment des Hirnversagens!


1
In VB.NET neu markiert, da die Antwort auch dort funktioniert.
DrFloyd5

Kein DrFloyd5; funktioniert nicht unter VB.NET, oder?
Zanoni

16
Wenn ich im VB.Net-Team wäre, würde ich hinzufügen; als Kommentar zur nächsten Version der Sprache ...
Joel Coehoorn

4
Ich denke, VB-Programmierer sind hell genug, um das Äquivalent herauszufinden.
BlueRaja - Danny Pflughoeft

Nun, nur um sicherzugehen, jetzt müssen sie es nicht mehr.
PsychoData

Antworten:


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

Denken Sie jedoch daran, dass dies im Haupt-GUI-Thread die Aktualisierung Ihrer GUI blockiert (es wird sich "träge" anfühlen).

Entfernen Sie einfach das ;, damit es auch für VB.net funktioniert.


Wird das Programm nach dem Aufruf von sleep in einer Methode weiterhin im Hintergrund ausgeführt (ohne neuen Thread zu erstellen)? Wenn ich in einem neuen Thread den Ruhezustand aufrufe, wird der Hauptthread dann seine Arbeit fortsetzen?
Jay Nirgudkar

@ JayNirgudkar Der Thread, der Sleep aufruft, wird gestoppt. Andere Threads sind nicht betroffen.
Isak Savo

Dies ist nicht garantiert korrekt.
Akumaburn

150

Grundsätzlich gibt es 3 Möglichkeiten, in (fast) jeder Programmiersprache zu warten:

  1. Lose warten
    • Ausführen von Thread-Blöcken für eine bestimmte Zeit (= verbraucht keine Verarbeitungsleistung)
    • Für blockierte / wartende Threads ist keine Verarbeitung möglich
    • Nicht so genau
  2. Enges Warten (auch enge Schleife genannt)
    • Der Prozessor ist während des gesamten Warteintervalls SEHR ausgelastet (tatsächlich verbraucht er normalerweise 100% der Verarbeitungszeit eines Kerns).
    • Einige Aktionen können während des Wartens ausgeführt werden
    • Sehr präzise
  3. Kombination der vorherigen 2
    • Es kombiniert normalerweise eine Verarbeitungseffizienz von 1 und Genauigkeit + Fähigkeit, etwas von 2 zu tun.

für 1. - Lose Wartezeit in C #:

Thread.Sleep(numberOfMilliseconds);

Der Windows-Thread-Scheduler bewirkt jedoch eine Genauigkeit von Sleep()etwa 15 ms (sodass der Ruhezustand problemlos 20 ms warten kann, selbst wenn nur 1 ms gewartet werden soll).

für 2. - Enges Warten in C # ist:

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

Wir könnten auch DateTime.Nowoder andere Mittel zur Zeitmessung verwenden, sind aber Stopwatchviel schneller (und dies würde wirklich in einer engen Schleife sichtbar werden).

für 3. - Kombination:

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
}

Dieser Code blockiert den Thread regelmäßig für 1 ms (oder etwas länger, abhängig von der Zeitplanung des Betriebssystem-Threads), sodass der Prozessor für diese Blockierungszeit nicht ausgelastet ist und der Code nicht 100% der Prozessorleistung verbraucht. Zwischen dem Blockieren kann weiterhin eine andere Verarbeitung durchgeführt werden (z. B. Aktualisierung der Benutzeroberfläche, Behandlung von Ereignissen oder Durchführung von Interaktions- / Kommunikationsaufgaben).


1
Timer kann auch von Interesse sein
JonnyRaa

55

Sie können in Windows keine genaue Ruhezeit angeben . Dafür benötigen Sie ein Echtzeit-Betriebssystem. Das Beste, was Sie tun können, ist eine Mindestschlafzeit anzugeben . Dann ist es an dem Scheduler, Ihren Thread danach aufzuwecken. Und rufen Sie niemals.Sleep() den GUI-Thread auf.


44

Da Sie jetzt über die Async / Wait-Funktion verfügen, können Sie 50 ms lang am besten mit Task.Delay schlafen:

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

Wenn Sie auf .NET 4 (mit Async CTP 3 für VS2010 oder Microsoft.Bcl.Async) abzielen, müssen Sie Folgendes verwenden:

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

Auf diese Weise blockieren Sie den UI-Thread nicht.


Können Sie während dieser Verzögerung antworten, wenn es sich in einer Schleife befindet?
Teoman Shipahi

Nein, du kannst nicht. Ich glaube, es gibt eine FlushAsyncVersion.
Toni Petrina

6
Eine Alternative, für die keine asyncErklärung erforderlich ist, ist der AnrufTask.Delay(50).Wait();
stuartd


14
Thread.Sleep(50);

Der Thread wird für die angegebene Zeit nicht für die Ausführung durch das Betriebssystem geplant. Diese Methode ändert den Status des Threads, um WaitSleepJoin einzuschließen.

Diese Methode führt kein Standard-COM- und SendMessage-Pumpen durch. Wenn Sie in einem Thread mit STAThreadAttribute schlafen müssen, aber Standard-COM- und SendMessage-Pumping ausführen möchten, sollten Sie eine der Überladungen der Join-Methode verwenden, die ein Timeout-Intervall angibt.

Thread.Join

5

Zur besseren Lesbarkeit:

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

0

Ab .NET Framework 4.5 können Sie Folgendes verwenden:

using System.Threading.Tasks;

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

-1

Beste aus beiden Welten:

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);
    }
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.