我需要主线程必须等待异步函数完成的帮助

时间:2019-01-11 02:07:33

标签: c# async-await

我正在努力解决这个问题,我想我知道会发生什么,但是却无法解决问题。我将不胜感激。 基本上,我的演示代码是在要煮沸的水壶功能异步运行的情况下煮一杯咖啡,因为这需要很长时间。我一直在等待MakeACupOfCoffee,因为在整个过程完成之前,我不希望秒表计时。这很早就完成了,我知道为什么,但是我不知道如何让代码等待水壶沸腾,同时让其他所有内容继续。

感谢任何指针。

这是我的代码。

using System;
using System.Threading;
using System.Threading.Tasks;

namespace asyncawait
{
    class Program
    {
        static void Main(string[] args)
        {
            TimeACoffee();
        }

        private static async Task TimeACoffee()
        {
            System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
            stopwatch.Start();

            // MakeACupOfCoffee completes before WaitForTheKettleToBoil has finished, 
            // therefore the await doesn't behave as I want it to
            await MakeACupOfCoffee();

            stopwatch.Stop();
            Console.WriteLine($"\n\nTime taken : {stopwatch.Elapsed}");

            Console.ReadLine();
        }

        private static async Task MakeACupOfCoffee()
        {
            // This function shouldn't return until everything has completed
            // I can't await here otherwise it'd be pointless doing asynchronously
            WaitForTheKettleToBoil();
            GetCup();
            AddCoffee();
            AddMilk();
            AddSugar();
        }

        private static Task WaitForTheKettleToBoil()
        {
            return Task.Run(() =>
            {
                Console.WriteLine("Waiting for the kettle to boil...");
                Thread.Sleep(8000);
            });
        }

        private static void AddMilk()
        {
            Console.WriteLine("Adding milk");
            Thread.Sleep(100);
        }

        private static void AddSugar()
        {
            Console.WriteLine("Adding sugar");
            Thread.Sleep(100);
        }

        private static void GetCup()
        {
            Console.WriteLine("Getting cup");
            Thread.Sleep(100);
        }

        private static void AddCoffee()
        {
            Console.WriteLine("Adding coffee");
            Thread.Sleep(100);
        }
    }
}

3 个答案:

答案 0 :(得分:4)

您的程序(让async完全传播)

注意 :由于这只是一个测试程序,所以这只是一个出色的解决方案,显然您可能不需要等待任何事情。

但是,由于这是一个async问题,因此我们可以await一个Task.Delay,而且由于C#7.x,我们可以使用async main方法

private static async Task TimeACoffee()
{
   var stopwatch = new System.Diagnostics.Stopwatch();
   stopwatch.Start();

   await MakeACupOfCoffee();

   stopwatch.Stop();
   Console.WriteLine($"\n\nTime taken : {stopwatch.Elapsed}");

   Console.ReadLine();
}

private static async Task MakeACupOfCoffee()
{
   await WaitForTheKettleToBoil();
   await GetCup();
   await AddCoffee();
   await AddMilk();
   await AddSugar();
}

private static async Task WaitForTheKettleToBoil()
{
   Console.WriteLine("Waiting for the kettle to boil...");
   await Task.Delay(100);
}

private static async Task AddMilk()
{
   Console.WriteLine("Adding milk");
   await Task.Delay(100);
}

private static async Task AddSugar()
{
   Console.WriteLine("Adding sugar");
   await Task.Delay(100);
}

private static async Task GetCup()
{
   Console.WriteLine("Getting cup");
   await Task.Delay(100);
}

private static async Task AddCoffee()
{
   Console.WriteLine("Adding coffee");
   await Task.Delay(100);
}

或者,您可以这样做

private static async Task MakeACupOfCoffee()
{

   // get the cup first, why not?
   await GetCup();

   // when this is all completed you have a coffee, though coffee drinkers may not like the order.
   await Task.WhenAll(WaitForTheKettleToBoil(), AddCoffee(), AddMilk(), AddSugar());
}

或者,您也可以这样做

private static void WaitForTheKettleToBoil()
{
   Console.WriteLine("Waiting for the kettle to boil...");
}

private static async Task MakeACupOfCoffee()
{
   // start the task (yehaa)
   var waitForTheKettleToBoilTask = Task.Run(WaitForTheKettleToBoil);

   // need a cup before we can add anything to it
   await GetCup();

   // when this is all completed you have a coffee
   await Task.WhenAll( AddCoffee(), AddMilk(), AddSugar(), waitForTheKettleToBoilTask);
}

注意 :首先喜欢咖啡牛奶和糖的人可能不喜欢你


来自ckuri的评论

哪些差异可能比我更清楚

  

应注意,您的代码的行为有很大不同。在你的   您煮的第一个代码,等待完成,拿起杯子,等待   完成后,添加咖啡,等待,添加牛奶等待,添加糖并等待。   但是,您可以选择得到杯子,等到得到杯子,   然后开始煮沸,在咖啡机中全部加入咖啡,牛奶和糖   同时等待,直到全部完成

答案 1 :(得分:1)

如果您想保持杯子的拿取和添加非异步的东西(如果这些都是快速操作,那是很好的选择),但是在执行所有这些操作时让水壶保持沸腾状态,则只需保存沸腾任务并返回:

public static Task MakeACupOfCoffee()
{
  var boilTask = WaitForKettleToBoil();
  GetCup();
  AddCoffee();
  AddMilk();
  AddSugar(); 
  return boilTask;
}

现在,煮沸(任务)开始, 煮沸时,您开始煮杯,添加咖啡,牛奶和糖,最后返回煮沸任务。因此,当您等待MakeACupOfCoffee时,它将等到水壶完成将水煮沸为止。

答案 2 :(得分:0)

如果您不能使用异步,为什么不使用Task.wait?

例如

var t = Task.Run( () => {
  // Action on here
} );

t.wait();

动作完成后将停止任务。