Statyczne metody w asp.net i asynchroniczność

0

Witajcie

Do późna mi się dzisiaj wzięło na programowanie i tak chyba moment zwątpienia mam, więc chcę tak sobie uporządkować kilka rzeczy:

Aplikacja asp.net core, kontroler wywołuje metodę serwisu o złożonej logice, więc wydzielam sobie w nim porcje kodu, którą umieszczam w osobnej statycznej klasie jako statyczną metodę (np parsowanke pliku). Żadnych globalnych zmiennych, wstrzykiwanych zależności typu kontekst do bazy danych. Jest To poprawne rozwiązanie?
A co w przypadku łączenia tego z asynciem? Dalej jest to poprawne rozwiązanie w asp.net? i tak muszę na wyniki poczekać awaitem by mi request asynca nie zabił gdy takimi statycznymi callami zacznę akcję typu walidacje, wysyłanie maily, czy komunikację z systemem zewnętrznym.

Jeśli te części workflowów w statycznych metodach miałaby jakieś zależności to wtedy powinno być jako instancja co by chociaż do unit testów móc wstrzykiwać zależności, prawda?

I na koniec await dla samego niegenerycznego Taska czyli nie asynchronicznie byłaby to zwykła metoda z voidem. Dzięki await wiem, że zakończenie przetwarzania takiego requesta nie zabije mi asynchronicznego wywołania np wysyłania mailów ale czy jednocześnie request zwróci mi dzięki temu szybciej czy jednak będzie czekał na zakończenie zadania awaita? Np takie wywołanie w requeście

await SmptClient.SendMailAsync(mail);

Czy może takie rzeczy powiniennem robić przez osobnego task runnera np hangfire? Tylko wtedy po co cały ten await?

0

Aplikacja asp.net core, kontroler wywołuje metodę serwisu o złożonej logice, więc wydzielam sobie w nim porcje kodu, którą umieszczam w osobnej statycznej klasie jako statyczną metodę (np parsowanke pliku). Żadnych globalnych zmiennych, wstrzykiwanych zależności typu kontekst do bazy danych. Jest To poprawne rozwiązanie?

Tak, zwykle robi się właśnie taką statyczną procedurę, która coś parsuje czy mapuje na jakiś np. persistence model.

A co w przypadku łączenia tego z asynciem? Dalej jest to poprawne rozwiązanie w asp.net? i tak muszę na wyniki poczekać awaitem by mi request asynca nie zabił gdy takimi statycznymi callami zacznę akcję typu walidacje, wysyłanie maily, czy komunikację z systemem zewnętrznym.

Nie rozumiem co chcesz osiągnąć. Moim zdaniem wątek powinien przelecieć to synchronicznie. Najpierw walidacja potem komunikacja z systemem zewnętrznym i wysłanie Emila jako rezultat tej pracy.

Jeśli te części workflowów w statycznych metodach miałaby jakieś zależności to wtedy powinno być jako instancja co by chociaż do unit testów móc wstrzykiwać zależności, prawda?

Statyczna metoda powinna używać statycznej zależności a taką zależność nawet łatwiej przetestować. Statyczna metoda powinna mieć punkt wejścia i wyjścia — przetwarzać coś i wypluwać wynik lub trzymać stan jakiejś konfiguracji.

I na koniec await dla samego niegenerycznego Taska czyli nie asynchronicznie byłaby to zwykła metoda z voidem. Dzięki await wiem, że zakończenie przetwarzania takiego requesta nie zabije mi asynchronicznego wywołania np wysyłania mailów ale czy jednocześnie request zwróci mi dzięki temu szybciej czy jednak będzie czekał na zakończenie zadania awaita? Np takie wywołanie w requeście
await SmptClient.SendMailAsync(mail);
Czy może takie rzeczy powiniennem robić przez osobnego task runnera np hangfire? Tylko wtedy po co cały ten await?

Nie wiem, czy dobrze rozumiem, ale jeśli mówisz o sytuacji, kiedy aplikacja przekroczy pulę wątków to tak może ci to pomóc, ale to prawdopodobnie nigdy się nie zdarzy. Jedyna sensowna sytuacja, jaką widzę to taka.

await SmptClient.SendMailAsync(mail1);
await SmptClient.SendMailAsync(mail2);

Czyli wykonanie dwóch metod naraz i czekanie na event który zwrócą.

0

Tak, o takie ciekawostki mi chodziło. Po co parsowanie asynchroniczne? Jak parsuje plik z dużą ilością danych, to jednocześnie mogę pobrać dane z bazy danych, które za chwilę będę przetwarzał, a sam proces ich selekcji też nie jest zwykłym selektem. W końcu chyba po to te wszystkie asyncowe rzeczy wymyślili :)

Task.WhenAll przydaje się do czekania na wynik, ale mi chodzi o zwykły task np wysłania maila, który nic nie zwraca. Czy w asp.net await będzie czekał na niego z wysłaniem responsa dla requesta usera czy po prostu danie awaita zapewnia, że wysłanie odpowiedzi nie zabije mi wykonującego się taska, którego zakończenie nie jest wymagane do zakończenia requesta.

Wysyłanie maila jest tu idealnym przypadkiem - ot wykonuję jakąś akcję updateu czegoś i przy okazji ma iść mail do kogoś ale mnie jako zaczynającego task updateu nie interesuje czy task wysyłania maila się skończył, czy rzucił errora bo nie ma takiego adresata itp ale chce mieć pewność, że nie zostanie ubity w trakcie, gdy już user dostanie odpowiedź z requesta z zupdateowanymi danymi.

Precyzując: czy wywołanie w kontrolerze

await akcja()

co nic nie zwraca blokuje requesta na czas wykonania czy też zwraca mi wynik requesta, a dana akcja się tam dalej robi i nie zostanie ubita. Do tej pory wszystkie ogólnie większe przetwarzania robiłem za pomocą Hangfire ale ten przypadek z wysyłaniem maila przez zwykłe await SmptClient.SendMailAsync(mail); mnie zastanawia.

2

Jak zrobisz await to request się nie skończy dopóki nie wykona się akcja na którą czeka await i dalsza kontynuacja.
Zaletą await przy zadaniach, które są ściśle powiązane z IO (własnie np. przepychanie maila przez sieć, albo odczyt czegoś z dysku) jest to, że zwalniasz wątek i on w tym czasie może wykonywać inne zadania. W przypadku metod synchronicznych wątek byłby zablokowany oczekiwaniem na odpowiedź, a nic poza tym by nie robił (bo by czekał na odpowiedź od urządzenia IO).

0
some_ONE napisał(a):

Jak zrobisz await to request się nie skończy dopóki nie wykona się akcja na którą czeka await i dalsza kontynuacja.
Zaletą await przy zadaniach, które są ściśle powiązane z IO (własnie np. przepychanie maila przez sieć, albo odczyt czegoś z dysku) jest to, że zwalniasz wątek i on w tym czasie może wykonywać inne zadania. W przypadku metod synchronicznych wątek byłby zablokowany oczekiwaniem na odpowiedź, a nic poza tym by nie robił (bo by czekał na odpowiedź od urządzenia IO).

Ok, czyli podsumowując sam await nie sprawi, że coś się wykona szybciej na samym requestcie w asp.net. Zatem

SmtpClient.Send(mailMessage);
await SmtpClient.SendMailAsync(mailMessage);

wykona się w identycznym czasie i nie przyśpieszy to w żadnym przypadku powrotu requesta.
Jedyna różnica jest taka, że drugi nie blokuje wątku requesta, co tak naprawdę ma dopiero znaczenie przy mocnym obciążeniu serwera. Dla zwykłej intranetowej apki na kilkudziesięciu/stu userów nic nie zmieni. Po prostu chcę się z tym utwierdzić.
Skąd całe te pytanie - coraz częściej widzę wszędzie te asynci i awaity na siłę wpychane (w podobnych akcjach jak chociażby ten przykład z wysyłaniem maila) bez żadnego faktycznego operowania na zwracanych taskach i czekania dopiero na wynik kilku równoległych. Dodanie chociaż jednego takiego bezsensownego awaita jak tutaj, powoduje że metody od początku wywołania na samym już kontrolerze musi być async i trzeba zmieniać kod kaskadowo przez kilka warstw.

0

An asynchronous request takes the same amount of time to process as a synchronous request. If a request makes a web service call that requires two seconds to complete, the request takes two seconds whether it's performed synchronously or asynchronously. However during an asynchronous call, a thread isn't blocked from responding to other requests while it waits for the first request to complete.>

Ok, znalazłem takie coś na stronach Microsoftu. Wniosek taki: robić asynci w asp.net dla jednego awaita w małych intranetowych aplikacjach dla ~kilkuset userów nie ma sensu. ThreadPool IIS'a dla requestów domyślnie wynosi 5000 i dopiero po takiej liczbie pojawi się nam 503 Server Busy.

3

Tak, w przypadku mało obciążonych apek webowych użycie asynchroniczności raczej nie da wymiernych korzyści. Ale niektóre klasy (np. HttpClient) mają tylko metody asynchroniczne, więc już się do tego przyzwyczaiłem ;)

Zaletę bardziej widać w apkach desktopowych, gdzie jest jeden wątek UI, który dzięki użyciu async-await nie zostanie zablokowany.

1

Ok a więc można przyjąć że zazwyczaj asynchronicznosc w mniejszych aplikacjach nie przyniesie wymiernych korzyści. Czy jest jednak coś przemawiajacego przeciwko domyślnemu stosowaniu asynchronicznosci? Bo jeśli nie to- moim zdaniem- i tak lepiej korzystać z asynchronicznosci jako że nie wiadomo czy w przyszłości się nie przyda i tym samym uniknąć konieczności zmiany istniejącego kodu.

Ponadto - poprawcie mnie jeśli się mylę - IIS thread pool jest jeden na wszystkie hostowane aplikacje, a tych przecież może być znacznie więcej niż ta jedna mała w której nie korzystamy z asynchronicznosci.

1

Zaletą kodu asynchronicznego jest mniejsze obciążenie serwera w pewnych przypadkach albo nie blokowanie wątku GUI.
Zaletą kodu synchronicznego jest to, że późniejsza zmiana na asynchroniczny to kupa roboty i przebijanie się przez wszystkie warstwy.
Dla mnie wybór jest dość prosty.

0

Musisz zrozumieć czym się różni kod atomowy od nieatomowego. Asynchroniczność ma sens jeśli wywołujesz naraz dwie operacje nieatomowe. Poczytaj tez na temat TPL.

1 użytkowników online, w tym zalogowanych: 0, gości: 1