Task.Delay ne zaman kullanılır, Thread.Sleep ne zaman kullanılır?


385

Ne zaman kullanılacağına ilişkin iyi bir kural (lar) var mı Task.Delay karşı Thread.sleep ?

  • Özellikle, birinin diğerine göre etkili / verimli olmasını sağlayacak minimum bir değer var mı?
  • Son olarak, Task.Delay bir async / await state makinesinde bağlam değiştirmeye neden olduğundan, onu kullanmanın ek yükü var mı?

2
10ms bilgisayar dünyasında bir çok döngü ...
Brad Christie

Ne kadar hızlı olmalı? Hangi performans problemleriniz var?
LB

4
Bence daha ilgili soru bunlardan herhangi birini hangi bağlamda kullanmayı planlıyorsunuz? Bu bilgi olmadan kapsam çok geniştir. Etkili / verimli ile ne demek istiyorsun? Doğruluktan, güç verimliliğinden vs. bahsediyor musunuz? Bunun hangi bağlamda önemli olduğunu bilmek çok merak ediyorum.
James World

4
Minimum değer 15.625 ms'dir, saat kesme hızından daha düşük değerlerin etkisi yoktur. Görev Gecikmesi her zaman bir Sistemi yakar.Dişleme Zamanlayıcısı, Uyku'nun ek yükü yoktur. Hiçbir şey yapmayan bir kod yazarken ek yük konusunda endişelenmezsiniz.
Hans Passant

Bahsetmediğim bir şey, ama önemli olduğunu düşünüyorum, Görev.Gecikme bir CancellationToken destekler, yani, örneğin bir döngü sürecini yavaşlatmak için kullanıyorsanız, gecikmeyi kesebilirsiniz. bu ayrıca işleminizin iptal etmek istediğinizde hızlı yanıt verebileceği anlamına gelir. ancak aynı işlemi Thread.Uyku döngüsü aralığını kısaltarak Token kılavuzunu kontrol edebilirsiniz.
Droa

Yanıtlar:


369

Thread.SleepGeçerli iş parçacığını engellemek istediğinizde kullanın .

Task.DelayGeçerli iş parçacığını engellemeden mantıklı bir gecikme istediğinizde kullanın .

Verimlilik, bu yöntemlerle en büyük endişe kaynağı olmamalıdır. Birincil gerçek dünya kullanımları, milisaniyeler yerine saniyeler içinde olan I / O işlemleri için yeniden deneme zamanlayıcılarıdır.


3
Aynı birincil kullanım durumu: bir yeniden deneme zamanlayıcısı.
Stephen Cleary

4
Veya CPU'yu ana döngüde çiğnemek istemediğinizde.
Eddie Parker

5
@RoyiNamir: Hayır. "Başka bir iş parçacığı" yoktur. Dahili olarak, bir zamanlayıcı ile uygulanır.
Stephen Cleary

20
Verimlilik konusunda endişelenmemeniz önerisi kötü tavsiye edilir. Thread.Sleepbağlam anahtarına neden olan geçerli iş parçacığını engeller. Bir iş parçacığı havuzu kullanıyorsanız, bu da yeni bir iş parçacığının atanmasına neden olabilir. Her iki işlem de oldukça ağırken, Task.Delayvb. Tarafından sağlanan kooperatif çoklu görev , tüm bu ek yüklerden kaçınmak, verimi en üst düzeye çıkarmak, iptal edilmesine izin vermek ve daha temiz kod sağlamak için tasarlanmıştır.
Corillian

2
@LucaCremry onesi: I would use Thread.Sleep`ı senkronize bir yöntemin içinde beklemek. Ancak, bunu asla üretim kodunda yapmam; Deneyimlerime göre, Thread.Sleepgördüğüm her şey , düzgün bir şekilde düzeltilmesi gereken bir tür tasarım sorununun göstergesi oldu.
Stephen Cleary

243

Arasındaki en büyük fark Task.Delayve Thread.Sleepyani Task.Delayuyumsuz çalıştırmak için tasarlanmıştır. Task.DelayEşzamanlı kodda kullanmak mantıklı değildir . Thread.SleepEşzamansız kodda kullanmak ÇOK kötü bir fikirdir .

Normalde Task.Delay() şu awaitanahtar kelime ile arayacaksınız :

await Task.Delay(5000);

veya gecikmeden önce bir kod çalıştırmak isterseniz:

var sw = new Stopwatch();
sw.Start();
Task delay = Task.Delay(5000);
Console.WriteLine("async: Running for {0} seconds", sw.Elapsed.TotalSeconds);
await delay;

Bil bakalım bu ne yazdıracak? 0.0070048 saniye çalışıyor. Bunun yerine await delayyukarı hareket edersek Console.WriteLine, 5.0020168 saniye boyunca Çalışıyor yazdıracaktır.

Aradaki farka bakalım Thread.Sleep:

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: Starting");
        Task delay = Task.Delay(5000);
        Console.WriteLine("async: Running for {0} seconds", sw.Elapsed.TotalSeconds);
        await delay;
        Console.WriteLine("async: Running for {0} seconds", sw.Elapsed.TotalSeconds);
        Console.WriteLine("async: Done");
    }

    static void syncCode()
    {
        var sw = new Stopwatch();
        sw.Start();
        Console.WriteLine("sync: Starting");
        Thread.Sleep(5000);
        Console.WriteLine("sync: Running for {0} seconds", sw.Elapsed.TotalSeconds);
        Console.WriteLine("sync: Done");
    }
}

Bunun ne yazdıracağını tahmin etmeye çalışın ...

eşzamansız:
Eşzamansız çalıştırma: 0,0070048 saniye
senkronizasyon için çalışıyor: Eşzamansız başlatma
: 5,0119008 saniye çalışır
Async: Bitti
senkronizasyon: 5,0020168 saniye
senkronizasyon için çalışıyor : Bitti

Ayrıca, Thread.Sleepçok daha doğru olduğunu fark etmek ilginçtir , ms doğruluğu gerçekten bir sorun değildir, Task.Delayminimum 15-30ms sürebilir. Her iki fonksiyondaki ek yük, sahip oldukları ms doğruluğuna kıyasla minimumdur ( Stopwatchdaha doğru bir şeye ihtiyacınız varsa Class'ı kullanın ). Thread.SleepHala İpliğinizi bağlar, Task.Delaybeklerken başka işler yapmak için serbest bırakın.


15
Neden "Asenkron kodda Thread.Sleep kullanmak çok kötü bir fikir"?
sunside

69
@sunside Async kodunun en önemli avantajlarından biri, çağrıları engellemekten kaçınarak bir iş parçacığının aynı anda birden fazla görev üzerinde çalışmasına izin vermektir. Bu, çok sayıda bireysel iş parçacığı ihtiyacını ortadan kaldırır ve bir iş parçacığı havuzunun birçok talebe aynı anda hizmet vermesini sağlar. Ancak, zaman uyumsuz kodun genellikle iş parçacığı üzerinde çalıştığı göz önüne alındığında, tek bir iş parçacığının gereksiz yere engellenmesi, Thread.Sleep()başka bir yerde kullanılabilecek tüm iş parçacığını tüketir. Thread.Sleep () ile birçok görev yürütülürse, tüm threadpool ipliklerini tüketme ve performansı ciddi şekilde engelleme şansı yüksektir.
Ryan

1
Anla. asyncKullanılmaya teşvik edildikleri için yöntem anlamında eşzamansız kod kavramını kaçırıyordum . Temelde sadece bir Thread.Sleep()threadpool iş parçacığında çalıştırmak kötü bir fikir, genel olarak kötü bir fikir değil. Sonuçta TaskCreationOptions.LongRunning, (cesaret kırılmış olsa da) Task.Factory.StartNew()rotaya giderken var.
sunside

6
için kudosawait wait
Eric Wu

2
@Reyhn Bu konudaki belgeler Tasl.Delaysistem zamanlayıcısını kullanmaktadır. "Sistem saati" sabit bir hızda "kenetlendiğinden", sistem zamanlayıcının tik hızı yaklaşık 16 ms'dir, talep ettiğiniz herhangi bir gecikme, sistem saatinin birkaç kenesine yuvarlanır ve ilk zamana kadar kaydırılır. işaretleyin. Task.Delay Docs.microsoft.com/en-us/dotnet/api/… adresindeki msdn belgelerine bakın ve açıklamalara ilerleyin.
Dorus

28

geçerli iş parçacığı öldürülmüş ve kullanıyorsanız Thread.Sleepve yürütüyorsa o zaman bir alabilirsiniz ThreadAbortException. İle Task.Delayher zaman bir iptal belirteci sağlayabilir ve incelikle öldürebilirsiniz. Bu, seçmemizin bir nedeni Task.Delay. bkz. http://social.technet.microsoft.com/wiki/contents/articles/21177.visual-c-thread-sleep-vs-task-delay.aspx

Ayrıca, bu durumda verimliliğin çok önemli olmadığı konusunda hemfikirim.


2
Şu durum var varsayalım: await Task.Delay(5000). Görevi öldürdüğümde TaskCanceledException(ve bastırdığımda) iş parçam hala hayatta. Temiz! :)
AlexMelw

24

Bir şey eklemek istiyorum. Aslında, Task.Delayzamanlayıcı tabanlı bir bekleme mekanizmasıdır. Eğer kaynağa bakarsanız Timer, gecikmeden sorumlu bir sınıfa başvurursunuz. Öte yandan Thread.Sleepaslında mevcut iş parçacığı uyku yapar, bu şekilde sadece bir iş parçacığı engelliyor ve boşa harcıyorsunuz. Zaman uyumsuz programlama modelinde, Task.Delay()bir gecikmeden sonra bir şey (devam) olmasını istiyorsanız her zaman kullanmalısınız .


'await Task.Delay ()', zamanlayıcı sona erene kadar iş parçacığını serbest bırakır,% 100 temizlenir. Peki, yöntem 'async' öneki olmadığı için 'await' kullanamazsam ne olur? Sonra sadece 'Task.Delay ()' diyebilirim. Bu durumda iplik hala engellenir, ancak Gecikmeyi () iptal etme avantajım vardır . Bu doğru mu?
Erik Stroeken

5
@ErikStroeken İptal simgelerini iş parçacığına ve göreve iletebilirsiniz. Task.Delay (). Wait () engellenirken, Task.Delay () beklemeden kullanılırsa görevi oluşturur. Bu görevle ne yapacağınız size kalmış, ancak konu devam ediyor.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.