Dlaczego w .NET Web API jest wymagana metoda, która asynchronicznie odczytuje zawartość odpowiedzi HTTP, biorąc pod uwagę, że istnieje już metoda asynchronicznego wykonania żądania?
Ponieważ może. Te dwie metody robią różne rzeczy. Pierwszy wysyła żądanie sieciowe przez przewód, drugi odczytuje z otrzymanego Stream
.
Ponieważ zarówno żądanie sieciowe, jak i odczyt ze strumienia są operacjami związanymi z identyfikacją IO, można skorzystać z apiksu async, który eksponują.
jeśli używam HttpClient.GetAsync (lub PostAsync lub PutAsync itp), to kod naprawdę więcej asynchroniczny również poprzez odczytywanie treści z asynchronicznie? Jeśli tak, jak/dlaczego?
To dziwne, że coś jest "bardziej asynchroniczne". Ale tak, pierwszy przykład jest bardziej asynchroniczny niż ten drugi.
Spróbujmy zobrazować następujący scenariusz: Tworzysz bibliotekę, która jest odpowiedzialna za rozmowę z usługą strony trzeciej. Odsłaniasz metodę, nazwijmy ją FooAsync
, która zwraca bardzo dużą wartość List<Foo>
. Użytkownik wie, że interfejs API jest asynchroniczny, więc dobrze czuje się wywoływanie go z wątku interfejsu użytkownika i nie przejmuje się blokowaniem go przez dłuższy czas.
Teraz, pozwala zobaczyć, co happeneds kiedy sprawia, że połączenia z każdej metody:
Wykonujemy FooAsync
i żądanie HTTP jest wykonany, uzyskując kontrolę do rozmówcy po osiągnięciu pierwszego await
. Następnie kontynuuje wykonywanie uderzenia w drugie await
, które czyta z odebranego strumienia, ponownie zwracając kontrolę dzwoniącemu, aż to się skończy. Przez cały czas interfejs użytkownika może przetwarzać komunikaty, ponieważ obie operacje są wykonywane asynchronicznie.
Wykonujemy FooAsync
, a my wykonujemy żądanie http. dajemy kontrolę nad pierwszym await
, wszystko jest w porządku. Następnie otrzymujemy odpowiedź i synchronicznie odczytujemy strumień bazowy. Podczas gdy czytamy (i pamiętamy, że czytamy bardzo duży strumień) wątek interfejsu użytkownika jest blokowany w operacji IO, nie może przetwarzać żadnych innych komunikatów.
Nasz drugi przypadek jest zdecydowanie niepożądany, a nawet gorszy, nieoczekiwany.Powiedzieliśmy użytkownikowi, że otrzymuje api async
, ale kończymy blokowanie przez dość długi czas. Nie tylko to, ale jeśli zostanie wywołane Task.Result
z wątku UI, może to spowodować zakleszczenie.
Zaletą korzystania z usługi await
w obu operacjach jest fakt, że użytkownik tworzy prawdziwie asynchroniczne API, nie marnując czasu na blokowanie operacji IO i nie zaskakując każdego, kto wywoła tę metodę blokując.
Proponuję przeczytać Best Practices in Asynchronous Programming, która mówi o wszystkich tych przypadkach krawędzi.
Podsumowując, jeśli możesz przejść asynchronicznie "na całą drogę", zrób to.
Czy uważasz, że ma to coś wspólnego z obsługą buforowanych treści? W rzeczywistości zawartość zostanie zwrócona w całości po wznowieniu. To nie jest operacja związana z obliczeniami, ale też pomieszana! Dobre pytanie! – brumScouse
dokumenty dla GetAsync mówią: "Zwrócony obiekt zadania zakończy się po odczytaniu całej odpowiedzi (w tym zawartości)." –