Mam znaczący sposób na opracowanie rozbudowanej aplikacji WPF, która będzie sterować zaawansowanym sprzętem za pośrednictwem komunikatorów szeregowych. Na samym dole aplikacji "stos" mam seryjny poziom komunikacyjny (wykorzystujący klasę .Net "SerialPort"). Czytanie i pisanie do urządzenia h/w jest podstawową częścią systemu, wykorzystywaną przez wiele różnych obszarów warstwy logiki biznesowej, często przeplatanych złożonymi obliczeniami naukowymi i inną taką logiką; te metody BLL są z kolei wywoływane z całego poziomu warstwy interfejsu użytkownika.Czy powinienem używać asynchronicznego "do końca" dla mojej aplikacji GUI?
Obecnie wszystko w warstwie logiki biznesowej, w tym odczyt i zapis SerialPort, jest synchroniczne. Jedyny przypadek, w którym używam async/await, znajduje się w warstwie interfejsu użytkownika, zazwyczaj podczas wywoływania logiki biznesowej. Tutaj będę owijać połączenia w Task.Run()
, e.g.:-
private async void SomeButtonClick(object sender, EventArgs e)
{
await Task.Run(() => _someBLLService.TurnPumpOn());
}
Jest to prosty przykład, który zajmuje się kwestią milisekund. Bardziej złożonym przykładem byłoby rozpoczęcie długotrwałego procesu (ponownie przy użyciu powyższej techniki); ta "usługa" logiki biznesowej będzie działać przez kilka sekund lub minut, zbierając dane ze sprzętu i wykonując inne funkcje "kontrolne" w tym czasie. Okresowo będzie transmitować dane z powrotem do interfejsu użytkownika w celu wykreślania na wykresie (za pośrednictwem struktury agregatora zdarzeń pubsub). Powyższa technika działa dobrze, dzięki czemu interfejs użytkownika pozostaje responsywny, podczas gdy takie procesy warstwy biznesowej mają miejsce.
Niedawno rozważałem przejście "asynchronizacji do końca", zaczynając od kodu komunikacji szeregowej (na przykład za pomocą .ReadAsync
), ale miałoby to reperkusje w całym systemie. Dziesiątki (jeśli nie setki) metod logiki biznesowej powinny być refaktoryzowane w metody asynchroniczne, aż do warstwy interfejsu użytkownika. Tu będę w stanie uprościć nieco powyższy kod:
private async void SomeButtonClick(object sender, EventArgs e)
{
await _someBLLService.TurnPumpOn();
}
Choć nie jestem przeciwny walce dużych zadań refaktoryzacji, zastanawiam się, jakie korzyści są naprawdę. Wielu ludzi (np. Stephen Cleary) popiera rozwiązanie "asynchroniczne", ale głównym celem wydaje się być utrzymywanie czułości interfejsu użytkownika podczas wywoływania długotrwałego procesu BLL, który już wykonuje moja technika Task.Run()
.
Wyjaśnienie, "asynchronizacja do końca" to inny sposób powiedzenia "nie blokuj kodu asynchronicznego" - działa tylko w jedną stronę.W przypadku aplikacji UI podstawową zaletą async jest responsywność, a 'await Task.Run' to doskonałe rozwiązanie, jeśli ci to działa. –