Quando eu descomento await Task.Delay(1_000);
, foo.DoAsync
within Task.Run
é Task.CompletedTask
porque ele espera por Task.Run
overhead. Então ele roda normalmente.
Quando eu comento await Task.Delay(1_000);
, foo.DoAsync
dentro do Task.Run é ele mesmo. Após o primeiro hit do breakpoint2 no modo de depuração, ele não atinge mais o breakpoint2.
internal class Foo
{
public Task DoAsync { get; set; }
public void Recursive()
{
// Breakpoint1
Recursive();
}
}
var foo = new Foo() { DoAsync = Task.CompletedTask };
//foo.Recursive();
Console.WriteLine($"Outer ThreadId: {Environment.CurrentManagedThreadId}");
var task = Task.Run(async () =>
{
Console.WriteLine($"Inner ThreadId: {Environment.CurrentManagedThreadId}");
// Breakpoint2
await foo.DoAsync;
Console.WriteLine("""
******
******
******
done
******
******
******
""");
});
await Task.Delay(1_000);
foo.DoAsync = task;
await foo.DoAsync;
Eu esperava que ele atingisse o breakpoint2 infinitamente, assim como foo.Recursive
atingiria o breakpoint1 infinitamente até que ele travasse. Para onde vai o fluxo de controle após o acerto inicial no breakpoint2?
O
Task
criado peloTask.Run
está sendo executado apenas uma vez. Ele não está sendo executado novamente toda vez que vocêawait
o executa. Esse é um equívoco comum, que também me pegou desprevenido quando eu estava aprendendo programação assíncrona.A
await
declaração é uma operação passiva. Ela apenas espera a conclusão da tarefa, a menos que a tarefa já esteja concluída, caso em que ela continua imediatamente para a próxima declaração. Issoawait
não afeta o estado da tarefa. Ela não causa a execução da tarefa se ela ainda não tiver sido iniciada, e não causa seu reinício se ela já tiver sido concluída.