Ваша программа начинается с вызова Main
и завершается по завершении.
Поскольку Main
просто создает экземпляр Program
, а затем вызывает MakeBreakfast()
, который возвращает Task
вернуться к основному, как только он достигнет своего первого await
.Таким образом, Main
существует почти сразу.
Давайте немного изменим код, чтобы увидеть, так ли это:
static void Main(string[] args)
{
Program p = new Program();
p.MakeBreakfast();
Console.WriteLine("Done!");
Console.ReadLine();
}
public async Task MakeBreakfast()
{
Console.WriteLine("Starting MakeBreakfast");
Thread.Sleep(1000);
Console.WriteLine("Calling await BoilWater()");
await BoilWater();
Console.WriteLine("Done await BoilWater()");
StartToaster();
PutTeainWater();
PutBreadinToaster();
SpreadButter();
}
Теперь, если я позволю этому запуску завершиться, я увижу этот вывод:
Starting MakeBreakfast
Calling await BoilWater()
BoilWater start
Done!
BoilWater end
Done await BoilWater()
StartToaster start
PutTeainWater start
StartToaster end
PutBreadinToaster start
SpreadButter start
SpreadButter end
PutTeainWater end
PutBreadinToaster end
Код действительно набирает await
и затем возвращается к Main
.
Чтобы сделать код правильным, нам нужно await
все.У вас есть два способа сделать это:
(1)
static async Task Main(string[] args)
{
Program p = new Program();
await p.MakeBreakfast();
Console.WriteLine("Done!");
Console.ReadLine();
}
public async Task MakeBreakfast()
{
await BoilWater();
await StartToaster();
await PutTeainWater();
await PutBreadinToaster();
await SpreadButter();
}
Теперь, когда это запустится, вы получите такой вывод:
BoilWater start
BoilWater end
StartToaster start
StartToaster end
PutTeainWater start
PutTeainWater end
PutBreadinToaster start
PutBreadinToaster end
SpreadButter start
SpreadButter end
Done!
(2)
static async Task Main(string[] args)
{
Program p = new Program();
await p.MakeBreakfast();
Console.WriteLine("Done!");
Console.ReadLine();
}
public async Task MakeBreakfast()
{
var tasks = new[]
{
BoilWater(),
StartToaster(),
PutTeainWater(),
PutBreadinToaster(),
SpreadButter(),
};
await Task.WhenAll(tasks);
}
Теперь эта версия запускает все задачи завтрака одновременно, но ждет их завершения, прежде чем вернуться.
Вы получите такой вывод:
BoilWater start
StartToaster start
PutTeainWater start
PutBreadinToaster start
SpreadButter start
StartToaster end
SpreadButter end
BoilWater end
PutTeainWater end
PutBreadinToaster end
Done!
Альтернатива, которая дает более логичное выполнение кода - вскипятите воду, затем заварите чай;и начать тостер, приготовить тост, намазать тост - может быть так:
public async Task MakeBreakfast()
{
async Task MakeTea()
{
await BoilWater();
await PutTeainWater();
}
async Task MakeToast()
{
await StartToaster();
await PutBreadinToaster();
await SpreadButter();
}
await Task.WhenAll(MakeTea(), MakeToast());
}
Это дает:
BoilWater start
StartToaster start
StartToaster end
PutBreadinToaster start
BoilWater end
PutTeainWater start
PutTeainWater end
PutBreadinToaster end
SpreadButter start
SpreadButter end
Done!