Eric Lippert的异步编程示例

时间:2017-08-24 20:55:00

标签: c# asynchronous

我试图从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();
        }
    }
}

2 个答案:

答案 0 :(得分:3)

这些Async方法中的每一个都返回一个可以await编辑的任务。 当你调用xxxAsync方法时,你开始异步操作,但是,当你await在同一行上的结果(这是任务)时,你告诉程序&#34;我需要结果在继续&#34;之前的这种方法。

我在示例中看到的只能并行运行的方法是ObtainIngredientsAsyncObtainRecipeAsync。所有其他方法都需要先前方法的结果。

如果您希望这些提及的方法并行运行,请首先调用这两种方法而不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);
}