Joe Duffy (autor Concurrent Programming on Windows) pisze w this blog article, że Thread.Sleep (1) jest preferowany w stosunku do Thread.Sleep (0), ponieważ zawiesza się dla wątków o tym samym i niższym priorytecie, a nie tylko dla równych wątków priorytetowych, jak dla Thread.Sleep (0).Czy Thread.Sleep (1) jest wyjątkowe?
Funkcja Thread.Sleep (0) jest wyjątkowa, zawiesza ten wątek i umożliwia wykonanie innych wątków oczekujących. Ale nic nie mówi o Thread.Sleep (1) (dla dowolnej wersji .NET).
Tak, czy Thread.leep (1) rzeczywiście robi coś specjalnego?
Tło:
mam orzeźwiający moją znajomość programowania współbieżnego. Napisałem trochę kodu C#, aby wyraźnie pokazać, że przyrosty i dekrety przed/po są nieatomowe i dlatego nie są bezpieczne dla wątków.
Aby uniknąć konieczności tworzenia setek wątków, umieszczam Thread.Sleep (0) po zwiększeniu wspólnej zmiennej, aby wymusić uruchomienie kolejnego wątku przez program planujący. Ta regularna zamiana nici czyni bardziej oczywistą nieatomową naturę przyrostu/spadku pre/post.
Wygląda na to, że Thread.Sleep (0) nie powoduje dodatkowego opóźnienia, zgodnie z oczekiwaniami. Jednak jeśli zmienię to na Thread.Sleep (1), wydaje się, że powraca do normalnego zachowania podczas snu (np. Otrzymuję z grubsza minimum 1ms opóźnienia).
Oznaczałoby to, że chociaż preferowane może być Thread.Sleep (1), dowolny kod, który używa go w pętli, działałby znacznie wolniej.
To pytanie na temat numeru "Could someone explain this interesting behaviour with Sleep(1)?" jest w pewnym sensie istotne, ale koncentruje się na C++ i po prostu powtarza wskazówki w artykule na blogu Joe Duffy.
Oto mój kod dla wszystkich zainteresowanych (skopiowany z LINQPad, więc może trzeba dodać klasę wokół niego):
int x = 0;
void Main()
{
List<Thread> threadList=new List<Thread>();
Stopwatch sw=new Stopwatch();
for(int i=0; i<20; i++)
{
threadList.Add(new Thread(Go));
threadList[i].Priority=ThreadPriority.Lowest;
}
sw.Start();
foreach (Thread thread in threadList)
{
thread.Start();
}
foreach (Thread thread in threadList)
{
thread.Join();
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
Thread.Sleep(200);
Console.WriteLine(x);
}
void Go()
{
for(int i=0;i<10000;i++)
{
x++;
Thread.Sleep(0);
}
}
Thread.Sleep (1) nie jest specjalny w tym sensie, że Sleep (2) lub Sleep (15) zrobią coś zasadniczo innego. Sleep (1) to tylko najniższa wartość wyższa niż Sleep (0), która * jest * specjalna (lub była). – Joren