617 Stimmen

Wann verwendet man Task.Delay, wann verwendet man Thread.Sleep?

Gibt es gute Regel(n) dafür, wann man Task.Delay versus Thread.Sleep verwenden sollte?

  • Gibt es speziell einen Mindestwert, der für eine effektive/effiziente Verwendung von einem gegenüber dem anderen angegeben werden muss?
  • Zuletzt, da Task.Delay auf einem async/await-Zustandsautomaten zu Kontextwechseln führt, entsteht hierbei ein Overhead bei der Verwendung?

604voto

Stephen Cleary Punkte 402664

Verwenden Sie Thread.Sleep, wenn Sie den aktuellen Thread blockieren möchten.

Verwenden Sie await Task.Delay, wenn Sie eine logische Verzögerung ohne Blockieren des aktuellen Threads wünschen.

Effizienz sollte keine oberste Priorität bei diesen Methoden sein. Ihr primärer realer Verwendungszweck liegt als Wiederversuch-Timer für I/O-Operationen, die im Bereich von Sekunden liegen, anstatt von Millisekunden.

375voto

Dorus Punkte 6706

Der größte Unterschied zwischen Task.Delay und Thread.Sleep besteht darin, dass Task.Delay dazu gedacht ist, asynchron ausgeführt zu werden. Es macht keinen Sinn, Task.Delay im synchronen Code zu verwenden. Es ist eine SEHR schlechte Idee, Thread.Sleep im asynchronen Code zu verwenden.

Normalerweise ruft man Task.Delay() mit dem await Schlüsselwort auf:

await Task.Delay(5000);

Oder, wenn du etwas Code vor der Verzögerung ausführen möchtest:

var sw = new Stopwatch();
sw.Start();
Task delay = Task.Delay(5000);
Console.WriteLine("async: Läuft für {0} Sekunden", sw.Elapsed.TotalSeconds);
await delay;

Vermutest du, was das drucken wird? Läuft für 0,0070048 Sekunden. Wenn wir das await delay über das Console.WriteLine verschieben, wird es Läuft für 5,0020168 Sekunden drucken.

Schauen wir uns den Unterschied mit Thread.Sleep an:

class Program
{
    static void Main(string[] args)
    {
        Task delay = asyncTask();
        syncCode();
        delay.Wait();
        Console.ReadLine();
    }

    static async Task asyncTask()
    {
        var sw = new Stopwatch();
        sw.Start();
        Console.WriteLine("async: Starten");
        Task delay = Task.Delay(5000);
        Console.WriteLine("async: Läuft für {0} Sekunden", sw.Elapsed.TotalSeconds);
        await delay;
        Console.WriteLine("async: Läuft für {0} Sekunden", sw.Elapsed.TotalSeconds);
        Console.WriteLine("async: Fertig");
    }

    static void syncCode()
    {
        var sw = new Stopwatch();
        sw.Start();
        Console.WriteLine("sync: Starten");
        Thread.Sleep(5000);
        Console.WriteLine("sync: Läuft für {0} Sekunden", sw.Elapsed.TotalSeconds);
        Console.WriteLine("sync: Fertig");
    }
}

Versuche vorherzusagen, was das drucken wird...

async: Starten
async: Läuft für 0,0070048 Sekunden
sync: Starten
async: Läuft für 5,0119008 Sekunden
async: Fertig
sync: Läuft für 5,0020168 Sekunden
sync: Fertig

Interessant ist auch zu bemerken, dass Thread.Sleep viel genauer ist, die Millisekunden-Genauigkeit ist kein wirkliches Problem, während Task.Delay mindestens 15-30ms dauern kann. Der Overhead bei beiden Funktionen ist minimal im Vergleich zur Millisekunden-Genauigkeit (verwende die Stopwatch Klasse, wenn du etwas genaueres benötigst). Thread.Sleep blockiert immer noch deinen Thread, während Task.Delay ihn freigibt, um andere Arbeiten zu erledigen, während du wartest.

41voto

crypted Punkte 9808

Ich möchte etwas hinzufügen. Tatsächlich ist Task.Delay ein timerbasiertes Wartemechanismus. Wenn Sie sich den Quellcode ansehen, finden Sie einen Verweis auf eine Timer-Klasse, die für die Verzögerung verantwortlich ist. Andererseits lässt Thread.Sleep tatsächlich den aktuellen Thread schlafen, wodurch Sie nur blockieren und einen Thread verschwenden. Im asynchronen Programmiermodell sollten Sie immer Task.Delay() verwenden, wenn Sie möchten, dass etwas (eine Fortsetzung) nach einer Verzögerung passiert.

33voto

Mr Balanikas Punkte 1637

Wenn der aktuelle Thread beendet wird und Sie Thread.Sleep verwenden und es ausgeführt wird, können Sie eine ThreadAbortException erhalten. Mit Task.Delay können Sie immer einen Abbruchtoken bereitstellen und ihn ordnungsgemäß beenden. Das ist ein Grund, warum ich Task.Delay wählen würde. Siehe http://social.technet.microsoft.com/wiki/contents/articles/21177.visual-c-thread-sleep-vs-task-delay.aspx

Ich stimme auch zu, dass Effizienz in diesem Fall nicht entscheidend ist.

10voto

telepuz Punkte 67

Delayed wäre ein besserer Name für Task.Delay - weil es keine bestehende Aufgabe verzögert, sondern stattdessen eine neue 'verzögerte' erstellt, die andererseits ausgelöst und die Ausführung des aktuellen Aufgabenkörpers aussetzen kann. Es ist im Grunde ein Timer, aber ohne Rückruf/Funktion.

Das Warten auf eine verzögerte Aufgabe erstellt ein neues Element in der async-Nachrichtenwarteschlange und blockiert keine Threads. Der gleiche Thread, in dem das Await aufgerufen wird, wird weiterhin an anderen Aufgaben arbeiten, falls vorhanden, und nach dem Timeout (oder wenn die vorherigen Elemente in der Warteschlange abgeschlossen sind) zum Await-Punkt zurückkehren. Auf der anderen Seite verwenden Aufgaben unter der Haube Threads - es können viele Aufgaben in einem einzigen Thread geplant und ausgeführt werden. Andererseits wird der Thread bei einem Aufruf von Thread.Sleep() blockiert, d.h. er wird für die angegebene Zeit außer Betrieb sein und keine async-Nachrichten aus der Warteschlange verarbeiten.

In .NET gibt es 2 Hauptansätze zur Parallelisierung. Der alte mit Threads, ThreadPools usw. Und der neue, basierend auf Tasks, async/await, TPL. Als Faustregel sollte man keine APIs aus diesen beiden Universen mischen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X