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?

3voto

Ehsan Ehsani Punkte 312

Ja, es gibt einige allgemeine Richtlinien dafür, wann Task.Delay versus Thread.Sleep verwendet werden sollte. Task.Delay ist die bevorzugte Methode für asynchrones Programmieren in C#, da sie es ermöglicht, asynchron zu warten, ohne einen Thread zu blockieren. Thread.Sleep blockiert den aufrufenden Thread und kann Leistungsprobleme in Anwendungen mit hoher Parallelität verursachen.

Es gibt keinen Mindestwert für Task.Delay, um effektiver oder effizienter als Thread.Sleep zu sein. Im Allgemeinen ist es am besten, Task.Delay zu verwenden, wenn Sie eine bestimmte Zeit warten müssen. Wenn Sie einen Thread für eine bestimmte Zeit blockieren müssen, verwenden Sie Thread.Sleep.

Was den Overhead bei der Verwendung von Task.Delay in einer async/await-Statusmaschine betrifft, gibt es einige Overheads beim Kontextwechsel. Dieser Overhead ist jedoch im Allgemeinen gering und wird von den Vorteilen des asynchronen Programmierens aufgewogen. Wenn Task.Delay korrekt verwendet wird, kann es helfen, die Reaktionsfähigkeit und Skalierbarkeit Ihrer Anwendung zu verbessern.

0voto

Jacek Punkte 1

Es ist auch erwähnenswert, dass Thread.Sleep(1) den GC schneller auslösen wird.

Dies basiert rein auf meinen und Teammitglieder Beobachtungen. Angenommen, Sie haben einen Dienst, der für jede spezifische Anfrage eine neue Aufgabe erstellt (ca. 200-300 laufend) und diese Aufgabe enthält viele schwache Referenzen im Ablauf. Die Aufgabe funktioniert wie eine Zustandsmaschine, daher haben wir Thread.Sleep(1) beim Zustandswechsel ausgeführt und dadurch die Speicherplatznutzung in der Anwendung optimiert - wie ich vorher sagte - dies wird dazu führen, dass der GC schneller ausgelöst wird. Es macht keinen so großen Unterschied bei Diensten mit geringem Speicherverbrauch (<1GB).

-1voto

Derf Skren Punkte 480

Ich hatte eine längere Diskussion mit einem Kollegen darüber und er hat mir bewiesen, dass es signifikante Unterschiede gibt, die über das hinausgehen, was die beste Antwort derzeit zeigt. Wenn du await Task.Delay(EinigeMillisekunden) verwendest, kannst du tatsächlich Aufrufer freigeben, die nicht direkt über dir im Stack stehen:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static async Task Main(string[] args)
        {
            Console.WriteLine("Gestartet " + Thread.CurrentThread.ManagedThreadId);
            DoSomething1();
            Console.WriteLine("Beendet " + Thread.CurrentThread.ManagedThreadId);
            Thread.Sleep(6000);
        }

        static async void DoSomething1()
        {
            Console.WriteLine("DoSomething1 Gestartet " + Thread.CurrentThread.ManagedThreadId);
            var result = await DoSomething2();
            Console.WriteLine("DoSomething1 Beendet " + Thread.CurrentThread.ManagedThreadId);
        }

        static async Task DoSomething2()
        {
            Console.WriteLine("DoSomething2 Gestartet " + Thread.CurrentThread.ManagedThreadId);

            await Task.Delay(5000);         // Wird DoSomething1 blockieren, aber Main freigeben
            //Thread.Sleep(5000);           // Wird alles blockieren, einschließlich Main
            //await Task.FromResult(5);     // Wird sofort zurückgegeben (nur zum Vergleich)
            //await Task.Delay(0);          // Was wird es tun, kannst du es erraten?

            Console.WriteLine("DoSomething2 Beendet " + Thread.CurrentThread.ManagedThreadId);
            return 0;
        }
    }
}

Spielen Sie mit diesem Code herum und beobachten Sie die unterschiedlichen Effekte der Verwendung von Delay oder Sleep. Die Erklärung geht über den Umfang dieser Antwort hinaus, kann aber zusammengefasst werden als "Async-Funktionen starten keinen neuen Thread, bis sie auf etwas warten, das nicht sofort ausgeführt werden kann (oder das Ergebnis bestimmt)". Dies ist die Ausgabe:

Gestartet 1
DoSomething1 Gestartet 1
DoSomething2 Gestartet 1
Beendet 1
DoSomething2 Beendet 4
DoSomething1 Beendet 4

Es geht nicht darum, dass DoSomething1(); in Main "fire and forget" ist. Das kannst du beweisen, indem du den Sleep verwendest. Beachte auch, dass wenn DoSomething2 aus Task.Delay "zurückkehrt", es auf einem anderen Thread läuft.

Diese Funktionen sind viel schlauer als ich dachte, und ich habe geglaubt, dass await einfach einen neuen Thread startet, um Dinge zu erledigen. Ich gebe immer noch nicht vor, alles zu verstehen, aber das gegen-intuitive Ergebnis oben zeigt, dass viel mehr unter der Oberfläche passiert, als nur Threads zu starten, um Code auszuführen.

-2voto

Ike Punkte 1114

Meine Meinung,

Task.Delay() ist asynchron. Es blockiert nicht den aktuellen Thread. Sie können immer noch andere Operationen innerhalb des aktuellen Threads ausführen. Es gibt einen Task-Rückgabetyp (Thread.Sleep() gibt nichts zurück). Sie können später nach einem anderen zeitintensiven Prozess überprüfen, ob diese Aufgabe abgeschlossen ist (verwenden Sie die Eigenschaft Task.IsCompleted).

Thread.Sleep() hat keinen Rückgabetyp. Es ist synchron. Im Thread können Sie nicht wirklich etwas anderes tun als auf das Ende der Verzögerung zu warten.

In Bezug auf den realen Einsatz, ich programmiere seit 15 Jahren. Ich habe Thread.Sleep() noch nie im Produktionscode verwendet. Ich konnte keinen Anwendungsfall dafür finden. Vielleicht liegt es daran, dass ich hauptsächlich Webanwendungen entwickle.

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