Gostaria de perguntar sua opinião sobre a arquitetura correta quando usar Task.Run
. Estou com a interface do usuário atrasada em nosso aplicativo WPF .NET 4.5 (com estrutura Caliburn Micro).
Basicamente, estou fazendo (trechos de código muito simplificados):
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();
}
}
Pelos artigos / vídeos que li / vi, sei que await
async
não é necessariamente executado em um thread em segundo plano e para iniciar o trabalho em segundo plano, você precisa envolvê-lo em espera Task.Run(async () => ... )
. O uso async
await
não bloqueia a interface do usuário, mas continua sendo executado no encadeamento da interface do usuário, tornando-o lento.
Onde é o melhor lugar para colocar o Task.Run?
Devo apenas
Encerre a chamada externa porque isso é menos trabalhoso para o .NET
, ou devo agrupar apenas métodos vinculados à CPU em execução internamente,
Task.Run
pois isso o reutiliza para outros lugares? Não tenho certeza aqui se iniciar um trabalho em threads de fundo no fundo é uma boa idéia.
Anúncio (1), a primeira solução seria assim:
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.
Anúncio (2), a segunda solução seria assim:
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());
deve ser simplesmenteawait Task.Run( () => this.contentLoader.LoadContentAsync() );
. AFAIK você não ganha nada adicionando um segundoawait
easync
dentroTask.Run
. E como você não está transmitindo parâmetros, isso simplifica um pouco mais aawait Task.Run( this.contentLoader.LoadContentAsync );
.