2009-10-24 17 views
7

Używam metod asynchronicznych w niektórych moich projektach i lubię to, ponieważ pozwala to mojej aplikacji być bardziej skalowalne. Zastanawiam się jednak, jak metody asynchroniczne naprawdę działają w tle? W jaki sposób .NET (lub Windows?) Wie, że połączenie zostało zakończone? W zależności od liczby wykonanych asynchronicznych wywołań, widzę, że tworzone są nowe wątki (nie zawsze jednak ...). Czemu?Jak działają metody asynchroniczne w języku C#?

Ponadto chciałbym monitorować, jak długo trwa wykonanie żądania. Aby przetestować koncepcję, napisałem następujący kod, który wywołuje asynchronicznie usługę sieci Web i natychmiast po uruchomieniu stopera.

for (int i = 0; i < 10000; i++) 
{ 
    myWebService.BeginMyMethod(new MyRequest(), result, new AsyncCallback(callback), i); 
    stopWatches[i].Start(); 
} 
// Call back stop the stopwatch after calling EndMyMethod 

To nie działa, ponieważ wszystkie wnioski (10000) mają taki sam czas rozpoczęcia i czas trwania będzie się liniowo (wezwanie 0 = czas trwania 1, połączenie 1 = czas trwania 2, itd.). Jak mogę monitorować rzeczywisty czas trwania połączenia metodą asynchroniczną (od momentu, gdy żądanie jest naprawdę wykonywane do końca)?


UPDATE: Czy metoda asynchroniczna zablokować przepływ? Rozumiem, że używa on .NET ThreadPool, ale jak IAsyncResult wie, że połączenie jest zakończone i nadszedł czas, aby zadzwonić do metody CallBack?

+0

1. ThreadPool, 2. Zobacz szczegóły na temat działania ThreadPool, ale nie sądzę, że to, co chcesz, jest możliwe w sposób ogólny. http://msdn.microsoft.com/en-us/library/ms973903.aspx –

Odpowiedz

3

Kod to linia kolejowa, a nitka to pociąg. Gdy pociąg jedzie na kolei, wykonuje kod.

BeginMyMethod jest wykonywany przez główny wątek. Jeśli zajrzysz do wnętrza BeginMyMethod, po prostu dodasz delegata z MyMethod do kolejki ThreadPool.Rzeczywista MyMethod jest wykonywana przez jeden z pociągów puli pociągu. Procedura wypełniania, która jest wywoływana po wykonaniu MyMethod, jest wykonywana przez ten sam wątek, który wykonał MyMethod, a nie przez główny wątek, który uruchamia resztę kodu. Podczas gdy wątek puli wątków jest zajęty wykonywaniem MyMethod, główny wątek może albo jeździć inną częścią systemu kolejowego (wykonać inny kod), albo po prostu spać, czekając aż jakiś semafor się zaświeci.

Dlatego nie ma czegoś takiego jak IAsyncResult "wiedząc", kiedy wywołać procedurę zakończenia, zamiast tego procedura zakończenia jest po prostu delegatem wywoływanym przez wątek puli wątku zaraz po zakończeniu wykonywania MyMethod.

Mam nadzieję, że nie przeszkadza ci nieco dziecinna analogia pociągów. Wiem, że pomógł mi niejednokrotnie wyjaśniając wielowątkowość ludziom.

+0

Podoba mi się analogia pociągu! Dzięki! :) – Martin

1

Najważniejsze jest to, że wywołanie Begin ustawia kolejki żądań do wykonania metody. Metoda jest faktycznie wykonywana w wątku ThreadPool, który jest zestawem wątków roboczych dostarczanych przez środowisko wykonawcze.

Pula wątków to ustalony zestaw wątków służących do przechodzenia przez asynchroniczne zadania, ponieważ są one umieszczane w kolejce. To wyjaśnia, dlaczego czas wykonywania jest dłuższy i dłuższy - wszystkie metody mogą być wykonywane w przybliżeniu w tym samym czasie, ale nie zaczynają się, dopóki nie zostaną wykonane wszystkie poprzednie metody w kolejce.

Aby monitorować czas potrzebny na wykonanie metody asynchronicznej, należy uruchomić i zatrzymać stoper na początku i na końcu metody.

Oto dokumenty dla klasy ThreadPool, a także artykuł o async methods, który lepiej tłumaczy, co się dzieje.

1

Metody asynchroniczne działają przy użyciu .NET ThreadPool. Popchną pracę na wątek ThreadPool (potencjalnie tworząc jeden w razie potrzeby, ale zwykle po prostu ponownie go wykorzystując), aby pracować w tle.

W twoim przypadku możesz zrobić to, co robisz, jednak zdaj sobie sprawę, że ThreadPool ma ograniczoną liczbę wątków, z którymi będzie działać. Będziesz dzielić swoją pracę na wątki w tle, a pierwsza uruchomi się natychmiast, ale po pewnym czasie będą ustawiać się w kolejce i nie będą działały, dopóki "zadania" nie zostaną wykonane całkowicie. Pozwoli to na pojawienie się wątków trwających dłużej i dłużej.

Jednak kryteria stopera są w pewnym stopniu błędne. Powinieneś zmierzyć całkowity czas potrzebny na wykonanie N zadań, a nie N razy, aby ukończyć jedno zadanie. Będzie to znacznie bardziej przydatna miara.

0

Możliwe, że większość czasu wykonania ma miejsce przed BeginMyMethod(). W takim przypadku twój pomiar będzie zbyt niski. W rzeczywistości, w zależności od interfejsu API, BeginMyMethod() może wywołać wywołanie zwrotne przed opuszczeniem samego stosu. Przeniesienie połączenia do StopWatch.Start() powinno pomóc wtedy.

Powiązane problemy