Chciałbym zapytać Cię o Twoją opinię na temat prawidłowej architektury, kiedy używać Task.Run
. Występuje opóźniony interfejs użytkownika w naszej aplikacji WPF .NET 4.5 (z ramą Caliburn Micro).
Zasadniczo robię (bardzo uproszczone fragmenty kodu):
public class PageViewModel : IHandle<SomeMessage>
{
...
public async void Handle(SomeMessage message)
{
ShowLoadingAnimation();
// Makes UI very laggy, but still not dead
await this.contentLoader.LoadContentAsync();
HideLoadingAnimation();
}
}
public class ContentLoader
{
public async Task LoadContentAsync()
{
await DoCpuBoundWorkAsync();
await DoIoBoundWorkAsync();
await DoCpuBoundWorkAsync();
// I am not really sure what all I can consider as CPU bound as slowing down the UI
await DoSomeOtherWorkAsync();
}
}
Z artykułów / filmów, które przeczytałem / widziałem, wiem, że await
async
niekoniecznie działa na wątku w tle i aby rozpocząć pracę w tle, musisz go owinąć Task.Run(async () => ... )
. Użycie async
await
nie blokuje interfejsu użytkownika, ale nadal działa w wątku interfejsu, więc powoduje, że jest on opóźniony.
Gdzie najlepiej umieścić Task.Run?
Powinienem tylko
Zawiń zewnętrzne wywołanie, ponieważ jest to mniej wątkowe dla platformy .NET
, czy powinienem zawijać tylko wewnętrznie działające metody związane z procesorem,
Task.Run
ponieważ dzięki temu można go używać w innych miejscach? Nie jestem tutaj pewien, czy dobrym pomysłem jest rozpoczęcie pracy nad wątkami w tle głęboko w rdzeniu.
Ad (1) pierwsze rozwiązanie wyglądałoby tak:
public async void Handle(SomeMessage message)
{
ShowLoadingAnimation();
await Task.Run(async () => await this.contentLoader.LoadContentAsync());
HideLoadingAnimation();
}
// Other methods do not use Task.Run as everything regardless
// if I/O or CPU bound would now run in the background.
Ad (2), drugie rozwiązanie wyglądałoby tak:
public async Task DoCpuBoundWorkAsync()
{
await Task.Run(() => {
// Do lot of work here
});
}
public async Task DoSomeOtherWorkAsync(
{
// I am not sure how to handle this methods -
// probably need to test one by one, if it is slowing down UI
}
await Task.Run(async () => await this.contentLoader.LoadContentAsync());
powinien po prostu byćawait Task.Run( () => this.contentLoader.LoadContentAsync() );
. AFAIK nic nie zyskujesz, dodając sekundęawait
iasync
wewnątrzTask.Run
. A ponieważ nie przekazujesz parametrów, upraszcza to nieco bardziejawait Task.Run( this.contentLoader.LoadContentAsync );
.