2013-01-17 7 views
8

Zacząłem uczyć programowania asynchronicznego w C# 5 i .Net 4.5 i jest coś, czego nie rozumiem.Programowanie asynchroniczne i oczekiwanie w pętli

private static int count; 

public static void Main() 
{ 
    LoopTest(); 

    Console.ReadKey(false); 
} 

static async void LoopTest() 
{ 
    count = 0; 

    for (var index = 0; index < 10; ++index) 
    { 
     Console.WriteLine("({0}) In Loop before await, Index {1}, Thread: {2}", count++, index, Thread.CurrentThread.ManagedThreadId); 
     await Task.Factory.StartNew(() => Thread.Sleep(10)); 
    } 
} 

Wynikiem jest:

(0) In Loop before await, Index 0, Thread: 9 
(1) In Loop before await, Index 1, Thread: 10  
(2) In Loop before await, Index 2, Thread: 11 
(3) In Loop before await, Index 3, Thread: 10 
(4) In Loop before await, Index 4, Thread: 11 
(5) In Loop before await, Index 5, Thread: 10 
(6) In Loop before await, Index 6, Thread: 12 
(7) In Loop before await, Index 7, Thread: 11 
(8) In Loop before await, Index 8, Thread: 10 
(9) In Loop before await, Index 9, Thread: 12 

więc istnieją różne wątki z dostępem do tej samej pętli? czy istnieje warunek wyścigu w zmiennej indeksowej?

+0

Należy wymienić oczekuj na Task.Factory.StartNew (() => Thread.Sleep (10)); z czekaniem na Task.Delay (10). Powinieneś puścić swój wątek przez 10 ms, nie trzymaj się go. –

+0

@publicENEMY Tak samo dzieje się 'Task.Delay';) –

+2

@ToniPetrina Thread.Sleep służy do trzymania wątku, aby symulować użycie wątku 10 ms. –

Odpowiedz

13

Nie, nie ma wyścigu. Zaczynasz nowe zadanie, które będzie działać w tle, ale twój kod nie będzie kontynuowany, dopóki to zadanie się nie zakończy, więc możesz być pewien, że twój kod będzie wykonywany tylko w jednym wątku w tym samym czasie.

Jednak ponieważ jest to aplikacja konsolowa, nie ma bieżącego SyncronizationContext. (W przeciwieństwie do aplikacji WinForm, WPF, ASP, Silverlight itp., W której będzie.) Oznacza to, że kontynuacja z dowolnego połączenia await będzie działać w puli wątków, a nie w wątku wywołującym. Więc tak, uruchamiasz jeden z wątków puli wątków w każdej iteracji pętli i za każdym razem może być inny, ale możesz być pewien, że, z wyjątkiem tego, co umieścisz w nowym zadaniu, będziesz " Zakończ "bieganie w dowolnym wątku przed rozpoczęciem pracy nad następnym, co zapewnia, że ​​w danym momencie jest tylko jeden wątek z kodem (co oznacza brak warunków wyścigu).

+0

Dzięki za odpowiedź! Rozumiem :) – m1o2

4

Co robisz nie jest naprawdę asycnhronous

await Task.Factory.StartNew(() => Thread.Sleep(10)); 

Stwarza to zadanie, a następnie czeka na to zadanie do wykonania. Możesz równie dobrze po prostu zadzwonić Thread.Sleep (10) tutaj.

Bardziej odpowiedni sposób to zrobić byłoby:

Task myTask = Task.Factory.StartNew(() => Thread.Sleep(10)); 
... do stuff here ... 
await myTask; // Now wait for the task to complete 

Jeśli chcesz wykonać szereg zadań w pętli, należy spojrzeć na metody Parallel.Foreach().

+0

Dzięki za odpowiedź! ale mam kilka pytań. jeśli tworzę zadanie na bieżącym wątku, kto tworzy resztę wątków? lub dlaczego ManagedThreadId ciągle się zmienia? – m1o2

+7

Przykład to przykład zabawek, w którym eksperymentuje i próbuje wyjaśnić wyniki. To nie wyjaśnia tych wyników i próbuje powiedzieć, że test jest błędny, kiedy nie ma niczego, co starałoby się na początek wyjaśnić, jak działa "czekanie". – Servy

+0

Przepraszamy, usunąłem z odpowiedzi błędne wyrażenie "w bieżącym wątku". Zadania są uruchamiane w puli wątków i nie muszą tworzyć tylu wątków, co zadań. Będzie próbował zarządzać zasobami, co jest jedną z zalet używania go w wątkach. – Pete