Po tym pytaniu czuję się komfortowo podczas korzystania z operacji asynchronicznych w ASP.NET MVC. Napisałem więc dwa posty na blogu na ten temat:
Mam w głowie zbyt wiele nieporozumień dotyczących operacji asynchronicznych w ASP.NET MVC.
Zawsze słyszę to zdanie: aplikacja może się lepiej skalować, jeśli operacje są wykonywane asynchronicznie
Często też słyszałem tego rodzaju zdania: jeśli masz duży ruch, lepiej nie wykonywać zapytań asynchronicznie - zużywanie 2 dodatkowych wątków do obsługi jednego żądania zabiera zasoby innym żądaniom przychodzącym.
Myślę, że te dwa zdania są niespójne.
Nie mam zbyt wielu informacji o tym, jak działa Threadpool w ASP.NET, ale wiem, że Threadpool ma ograniczony rozmiar dla wątków. Zatem drugie zdanie musi odnosić się do tej kwestii.
I chciałbym wiedzieć, czy operacje asynchroniczne w ASP.NET MVC używają wątku z ThreadPool na .NET 4?
Na przykład, kiedy implementujemy AsyncController, w jaki sposób struktury aplikacji? Jeśli otrzymuję duży ruch, czy warto zaimplementować AsyncController?
Czy jest ktoś, kto może zdjąć tę czarną zasłonę na moich oczach i wyjaśnić mi ofertę asynchronii w ASP.NET MVC 3 (NET 4)?
Edytować:
Przeczytałem poniższy dokument prawie setki razy i rozumiem główną sprawę, ale nadal mam zamieszanie, ponieważ jest tam zbyt wiele niespójnych komentarzy.
Korzystanie z kontrolera asynchronicznego w ASP.NET MVC
Edytować:
Załóżmy, że mam akcję kontrolera jak poniżej (nie jest to jednak implementacja AsyncController
):
public ViewResult Index() {
Task.Factory.StartNew(() => {
//Do an advanced looging here which takes a while
});
return View();
}
Jak widzisz, odpalam operację i zapominam o niej. Następnie wracam natychmiast, nie czekając na zakończenie.
W tym przypadku, czy to musi używać wątku z puli wątków? Jeśli tak, po zakończeniu, co się stanie z tym wątkiem? Czy GC
pojawia się i czyści zaraz po zakończeniu?
Edytować:
Aby uzyskać odpowiedź @ Darin, oto przykład kodu asynchronicznego, który komunikuje się z bazą danych:
public class FooController : AsyncController {
//EF 4.2 DbContext instance
MyContext _context = new MyContext();
public void IndexAsync() {
AsyncManager.OutstandingOperations.Increment(3);
Task<IEnumerable<Foo>>.Factory.StartNew(() => {
return
_context.Foos;
}).ContinueWith(t => {
AsyncManager.Parameters["foos"] = t.Result;
AsyncManager.OutstandingOperations.Decrement();
});
Task<IEnumerable<Bars>>.Factory.StartNew(() => {
return
_context.Bars;
}).ContinueWith(t => {
AsyncManager.Parameters["bars"] = t.Result;
AsyncManager.OutstandingOperations.Decrement();
});
Task<IEnumerable<FooBar>>.Factory.StartNew(() => {
return
_context.FooBars;
}).ContinueWith(t => {
AsyncManager.Parameters["foobars"] = t.Result;
AsyncManager.OutstandingOperations.Decrement();
});
}
public ViewResult IndexCompleted(
IEnumerable<Foo> foos,
IEnumerable<Bar> bars,
IEnumerable<FooBar> foobars) {
//Do the regular stuff and return
}
}