Solucionado (ver solução)
Solucionado
(ver solução)
1
resposta

Task.Run v.s Task.Factory.StartNew e .ConfigureAwait()

Bom dia, tenho 2 dúvidas sobre paralelismo que não foram apresentadas no curso.

A primeira é que por um tempo eu vi o uso do método Task.Run, mas buscando respostas na internet, falam que ele faz o mesmo que o Task.Factory.StartNew porém não recebe argumentos adicionais e é mais devagar, verdade?

A segunda é que depois de observar muitos projetos que trabalham com paralelismo, eu vi um método após fazer um "await" de uma Task o .ConfigureAwait(boolean), não entendi muito bem o que faz procurando na internet, mas me chamou a atenção de que em um tópico no StackOverFlow o mesmo disse que caso você use um desses você deve usar em todo o seu projeto, então o que faz e porque ter que usar em todos do seu projeto?

1 resposta
solução!

Oi Renan, tudo bem?

O Task.Run é implementado com a mesma lógica usada para Task.Factory.StartNew. A diferença é que ele já passa alguns parâmetros default.

A instrução:

Task.Run(acao);

equivale a:

Task.Factory.StartNew(acao, 
    CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);

Sobre sua segunda dúvida:

Digamos que você utilize o operador await num método assíncrono MeuMetodo() de uma aplicação windows forms.

public async Task<string> MeuMetodo()
{
    using (var resposta = await metodoABC())
    {
        return await resposta.MetodoXYZ();
    }
}

Um outro método MeuChamador() normalmente invocaria o MeuMétodo, de forma assíncrona, assim:

var resultado = await MeuMetodo();

Isso não provoca nenhum problema. Porém, se o chamador fizer uma chamada síncrona, tentando acessar a propriedade Result...

var resultado = MeuMetodo().Result;

Isso provocará um deadlock. Esse deadlock acontece porque numa aplicação Windows Forms existe uma thread principal (de interface de usuário). Quando você usa um método assíncrono, ele tenta "sincronizar" o contexto, rodando o método no contexto da thread da interface do usuário (thread principal). Como o MeuMetodo() ainda não terminou, também não é possível acessar a propriedade Result, causando um deadlock.

O método ConfigureAwait(false) configura a tarefa para que a continuação após o await não tenha que ser executada no contexto do chamador, evitando possíveis deadlocks ("bloqueios mortais" na thread). Com .ConfigureAwait(false), o código pode rodar numa outra thread (do thread pool) e assim evitamos o deadlock.

Por isso, você deve usar ConfigureAwait(false) em MeuMetodo(), para evitar que as chamadas síncronas provoquem deadlock na sua aplicação:

public async Task<string> MeuMetodo()
{
    using (var resposta = await metodoABC().ConfigureAwait(false))
    {
        return await resposta.MetodoXYZ().ConfigureAwait(false);
    }
}