Czy istnieją dobre reguły, kiedy należy używać Task.Delay kontra Thread.Sleep ?
- W szczególności, czy istnieje minimalna wartość zapewniająca, aby jedna była skuteczna / wydajna w stosunku do drugiej?
- Wreszcie, skoro Task.Delay powoduje przełączanie kontekstu na maszynie stanu asynchronicznie / oczekuj, czy jest narzut związany z jego używaniem?
Odpowiedzi:
Użyj,
Thread.Sleep
gdy chcesz zablokować bieżący wątek.Użyj,
Task.Delay
gdy chcesz logicznego opóźnienia bez blokowania bieżącego wątku.Efektywność nie powinna być najważniejszym problemem tych metod. Ich głównym zastosowaniem w świecie rzeczywistym są liczniki czasu ponawiania operacji we / wy, które są rzędu sekund, a nie milisekund.
źródło
Thread.Sleep
zablokuje bieżący wątek, który powoduje zmianę kontekstu. Jeśli używasz puli wątków, może to również spowodować przydzielenie nowego wątku. Obie operacje są dość ciężkie, podczas gdy wielozadaniowość kooperacyjna zapewniona przezTask.Delay
itp. Została zaprojektowana w celu uniknięcia całego tego narzutu, maksymalizacji przepustowości, umożliwienia anulowania i zapewnienia czystszego kodu.onesi: I would use
Thread.Sleep`, aby poczekać wewnątrz metody synchronicznej. Jednak nigdy nie robię tego w kodzie produkcyjnym; z mojego doświadczeniaThread.Sleep
wynika , że wszystko, co kiedykolwiek widziałem, wskazuje na jakiś problem projektowy, który należy odpowiednio naprawić.Największa różnica między
Task.Delay
iThread.Sleep
polega na tym, żeTask.Delay
ma on działać asynchronicznie. Nie ma sensu używaćTask.Delay
w kodzie synchronicznym. UżywanieThread.Sleep
w kodzie asynchronicznym jest BARDZO złym pomysłem .Zwykle zadzwonisz
Task.Delay()
zeawait
słowem kluczowym:lub, jeśli chcesz uruchomić jakiś kod przed opóźnieniem:
Zgadnij, co to wydrukuje? Działa przez 0,0070048 sekund. Jeśli zamiast tego przeniesiemy
await delay
powyższeConsole.WriteLine
, zostanie wydrukowany Uruchomiony przez 5.0020168 sekund.Spójrzmy na różnicę w
Thread.Sleep
:Spróbuj przewidzieć, co to wydrukuje ...
Warto również zauważyć, że
Thread.Sleep
jest o wiele dokładniejszy, dokładność ms nie jest tak naprawdę problemem, aTask.Delay
może zająć minimum 15-30 ms. Narzut na obie funkcje jest minimalny w porównaniu z dokładnością ms, jaką mają (użyjStopwatch
klasy, jeśli potrzebujesz czegoś dokładniejszego).Thread.Sleep
nadal wiąże Wątek,Task.Delay
zwolnij go, aby mógł wykonać inną pracę podczas oczekiwania.źródło
Thread.Sleep()
zużywa cały wątek, który w innym przypadku mógłby zostać użyty w innym miejscu. Jeśli wiele zadań jest uruchamianych za pomocą Thread.Sleep (), istnieje duże prawdopodobieństwo wyczerpania wszystkich wątków puli wątków i poważnego ograniczenia wydajności.async
metod, ponieważ zachęca się je do użycia. Zasadniczo jest to zły pomysł, aby działaćThread.Sleep()
w wątku puli wątków, a nie ogólnie zły pomysł. W końcu pojawia się drogaTaskCreationOptions.LongRunning
(choć zniechęcona)Task.Factory.StartNew()
.await wait
Tasl.Delay
wykorzystuje zegar systemowy. Ponieważ „Zegar systemowy„ tyka ”ze stałą szybkością.”, Prędkość tykania zegara systemowego wynosi około 16 ms, każde opóźnienie, o które poprosisz, zostanie zaokrąglone do pewnej liczby tyknięć zegara systemowego, z przesunięciem czasu do pierwszego kleszcz. Zobacz dokumentację msdn naTask.Delay
docs.microsoft.com/en-us/dotnet/api/... i przewiń w dół do uwag.jeśli bieżący wątek zostanie zabity, a ty użyjesz
Thread.Sleep
go i się wykonuje, możesz otrzymaćThreadAbortException
. DziękiTask.Delay
zawsze możesz podać token anulowania i z gracją go zabić. To jeden z powodów, dla których wybrałbymTask.Delay
. patrz http://social.technet.microsoft.com/wiki/contents/articles/21177.visual-c-thread-sleep-vs-task-delay.aspxZgadzam się również, że w tym przypadku wydajność nie jest najważniejsza.
źródło
await Task.Delay(5000)
. Gdy zabiję zadanie, dostajęTaskCanceledException
(i je pomijam), ale mój wątek wciąż żyje. Schludny! :)Chcę coś dodać. W rzeczywistości
Task.Delay
jest mechanizm oczekiwania oparty na zegarze. Jeśli spojrzysz na źródło , znajdziesz odniesienie doTimer
klasy odpowiedzialnej za opóźnienie. Z drugiej stronyThread.Sleep
faktycznie uśpia bieżący wątek, w ten sposób blokujesz i marnujesz jeden wątek. W modelu programowania asynchronicznego powinieneś zawsze używać,Task.Delay()
jeśli chcesz, aby coś (kontynuacja) wydarzyło się z pewnym opóźnieniem.źródło