За кулисами async / await создает конечный автомат на основе продолжений задач. Вы можете имитировать это, используя ContinueWith
и немного изобретательности (детали выходят за рамки этого ответа).
Что вам нужно знать, так это то, что он использует продолжения, и что продолжения - по умолчанию - происходят синхронно, по одному за раз.
В этом случае и B, и C создают продолжения на Init
. Эти продолжения будут идти за другим. Таким образом, когда C продолжается первым и входит в бесконечный цикл, он препятствует продолжению B.
Решение? Ну, кроме избежания бесконечных циклов, вы можете использовать задачу с асинхронными продолжениями. Простой способ сделать это поверх Task.Run
заключается в следующем:
var Init = Task.Run(async () =>
{
await Task.Delay(1000);
}).ContinueWith(_ => { }, TaskContinuationOptions.RunContinuationsAsynchronously);
Добавление
Согласно комментарию OP, бесконечный цикл представляет блокирующий вызов. Мы можем решить эту ситуацию другим подходом:
var TaskC = Task.Run(async () =>
{
await Init;
Console.WriteLine("C finished waiting");
await Task.Run(() => {while (true) { }});
});
Таким образом, блокирующий вызов не является продолжением Init
(вместо этого он будет продолжением продолжения), и, таким образом, он не будет препятствовать выполнению других продолжений Init
.