我试图从2011年的Asynchronous Programming - Easier Asynchronous Programming with the New Visual Studio Async CTP中使用Eric Lippert的例子来理解C#中异步编程的基础知识。
我已经为上一个代码示例中引用的方法填充了存根,我希望在命令行中看到的是:
Start obtain order
Finish obtain order
Start obtain ingredients
Start obtain recipe
Finish obtain ingredients
Finish obtain recipe
Start recipe prepare meal
Finish recipe prepare meal
Diner receives meal
但我反过来看到每个方法都被依次调用 - 似乎没有任何异步。
我的代码中是否有错误,或者我误解了它应该如何工作?
非常感谢任何指导。
namespace AsyncAwait
{
using System;
using System.Threading.Tasks;
internal class Program
{
internal class Order
{
}
internal class Ingredients
{
}
internal class Recipe
{
internal async Task<Meal> PrepareAsync(Ingredients ingredients)
{
Console.WriteLine("Start recipe prepare meal");
await Task.Delay(4 * 1000);
Console.WriteLine("Finish recipe prepare meal");
return new Meal();
}
}
internal class Meal
{
}
private class Diner
{
internal void Give(Meal meal)
{
Console.WriteLine("Diner receives meal");
}
}
async private static Task<Order>ObtainOrderAsync(Diner diner)
{
Console.WriteLine("Start obtain order");
await Task.Delay(3 * 1000);
Console.WriteLine("Finish obtain order");
return new Order();
}
async private static Task<Ingredients>ObtainIngredientsAsync(Order order)
{
Console.WriteLine("Start obtain ingredients");
await Task.Delay(2 * 1000);
Console.WriteLine("Finish obtain ingredients");
return new Ingredients();
}
async private static Task<Recipe>ObtainRecipeAsync(Order order)
{
Console.WriteLine("Start obtain recipe");
await Task.Delay(5 * 1000);
Console.WriteLine("Finish obtain recipe");
return new Recipe();
}
async private static void ServeBreakfast(Diner diner)
{
Order order = await ObtainOrderAsync(diner);
Ingredients ingredients = await ObtainIngredientsAsync(order);
Recipe recipe = await ObtainRecipeAsync(order);
Meal meal = await recipe.PrepareAsync(ingredients);
diner.Give(meal);
}
static void Main(string[] args)
{
Diner diner = new Diner();
ServeBreakfast(diner);
Console.ReadLine();
}
}
}
答案 0 :(得分:3)
这些Async
方法中的每一个都返回一个可以await
编辑的任务。
当你调用xxxAsync
方法时,你开始异步操作,但是,当你await
在同一行上的结果(这是任务)时,你告诉程序&#34;我需要结果在继续&#34;之前的这种方法。
我在示例中看到的只能并行运行的方法是ObtainIngredientsAsync
和ObtainRecipeAsync
。所有其他方法都需要先前方法的结果。
如果您希望这些提及的方法并行运行,请首先调用这两种方法而不await
,然后再继续await
这两种方法。
async private static void ServeBreakfast(Diner diner)
{
Order order = await ObtainOrderAsync(diner);
Task<Ingredients> ingredientsTask = ObtainIngredientsAsync(order);
Task<Recipe> recipeTask = ObtainRecipeAsync(order);
Ingredients ingredients = await ingredientsTask;
Recipe recipe = await recipeTask
Meal meal = await recipe.PrepareAsync(ingredients);
diner.Give(meal);
}
答案 1 :(得分:1)
您正在等待每项任务,一个接一个:
Order order = await ObtainOrderAsync(diner);
Ingredients ingredients = await ObtainIngredientsAsync(order);
Recipe recipe = await ObtainRecipeAsync(order);
Meal meal = await recipe.PrepareAsync(ingredients);
diner.Give(meal);
当您await
任务时,您将停止执行该方法,直到任务完成。
因此,您要为任务定义严格的逐个订单:在上一个任务完成之前,您不会启动任务。
这是一个示例,其中两个任务是并行完成的,这可以为您提供所期望的输出。
为了(希望)使代码更清晰,我已经将所有等待分解为单独的语句来创建任务并等待它们。
async private static void ServeBreakfast(Diner diner)
{
// first task is to get the order
Task<Order> getOrder = ObtainOrderAsync(diner);
// we need to wait for the order, then we
// can get the ingredients and recipe in parallel
Order order = await getOrder;
// ### Change from your logic: Here we're starting two tasks in parallel. ###
Task<Ingredients> getIngredients = ObtainIngredientsAsync(order);
Task<Recipe> getRecipe = ObtainRecipeAsync(order);
// once we have both the above we can make the meal
Ingredients ingredients = await getIngredients;
Recipe recipe = await getRecipe;
Task<Meal> getMeal = recipe.PrepareAsync(ingredients);
// when the meal is ready, give it to the diner
diner.Give(await getMeal);
}