程序在等待时退出

我有一个while循环,应该重复该程序,直到满足某个条件。 在这个循环中我调用异步函数,它为我打印一条消息。 这是(剪短)代码:

private void InitializeMessageSystem ( ) { do { // Do stuff await printMessage ("Hello World!"); Console.ReadKey(); } while (condition != true) } 

这里的函数printMessage()

 private static async Task printMessage (string message, int spd = 1) { int delay = 50 / spd; string[] words = message.Split(' '); int index = 1; for (int word = 0; word  Console.WindowWidth) { Console.WriteLine(); index = 1; } for (int c = 0; c < current.Length; c++) { Console.Write(current[c]); await Task.Delay(delay); } Console.Write(" "); } } 

编辑主函数的调用:

 static void Main (string[] args) { InitializeMessageSystem(); Console.ReadKey(); } 


当我在function尚未完成时按下某个键时,为什么我的程序会退出? 我以为程序会等待Console.ReadKey()直到函数printMessage()完成?

您的问题是await将程序的控制流返回给函数的调用者。 通常,当您等待的异步任务完成时,将继续执行。

因此,当您等待printMessage并且main现在等待键输入时,控制将返回到您的主函数。 当您按下main键返回操作系统时,您的进程(包括所有异步任务)将终止。

InitializeMessageSystem更改为

 private async Task InitializeMessageSystem ( ) 

并将main的代码更改为

 InitializeMessageSystem().Wait(); 

在等待密钥之前等待InitializeMessageSystem完全完成。

调用同步函数和异步函数之间的区别在于,在调用同步函数时,您知道在调用后到达语句时,函数将完全执行。 当调用异步函数时,该函数被调度为线程池中的任务,当池中的任何线程有时间执行该任务时。

这使得您有时间在其中一个线程执行任务时执行其他操作。 只要您需要结果,您就可以等待任务完成。

仅当您的函数也是异步时才有效。 如果你不使你的函数异步你不能使用async-await。 使您的函数异步和函数的客户端也是异步是真正使用async-await的唯一方法。 记住:所有异步函数都应返回Task而不是void和Task >而不是TResult。 唯一的例外是事件处理程序

 private async void Button1_Clicked(object sender, ...) { var myTask = SlowMultiplierAsync(4, 3); // while myTask is running you can do other things // after a while you need the result: int taskResult = await myTask; Process(taskResult); } private async Task SlowMultiplierAsync(int x, int y) { // let's take a nap before multiplying // do this by awaiting another async function: await Task.Delay(TimeSpan.FromSeconds(5)); return x * y; } 

如果您不希望(或可以)使您的函数异步,您可以通过使用task.Run启动任务来模拟类似的行为:

 private void InitializeMessageSystem ( ) { do { // Do stuff var myTask = task.Run( () => printMessage ("Hello World!")); myTask.Wait(); Console.ReadKey(); } while (condition != true) 

虽然这将确保您的function在任务完成之前不会结束,但您的function将是您的客户的同步function。 例如,它不会使您的UI响应。

这里有关于stackoverflow的Eric lippert曾经解释过我异步并发的区别。 链接到他的答案

假设你必须做早餐。 烤面包,煮一些鸡蛋。

  • 同步:开始烘烤面包。 等到烘烤完毕。 开始煮鸡蛋,等到鸡蛋煮熟。
  • 异步但不兼并:开始烘烤面包,而面包是烘烤开始煮鸡蛋。 虽然鸡蛋正在烹饪,你可以做其他事情,比如煮茶。 过了一会儿,你要等到鸡蛋煮熟,等到面包烤好。 这通常是异步等待。
  • 异步和并发:雇一个厨师烤面包,雇一个厨师煮鸡蛋,等到两个厨师都吃完了。 在这里,烘烤和烹饪由不同的线程完成。 这是最昂贵的方法

以下代码执行时没有任何错误或警告。 但是当你执行代码时,程序会以静默方式退出。 您可能期望的是程序等待任务完成,要求用户按任意键并退出。 实际发生的是在执行await语句之后控件返回到调用步骤。 在我们的情况下,步骤await task; 在任务完成之前执行,控制返回到调用步骤SomeTask(); 并退出程序。

 class Program { static void Main(string[] args) { SomeTask(); } public static async void SomeTask() { Task task = Task.Run(() => { System.Threading.Thread.Sleep(20000); Console.WriteLine("Task Completed!"); }); await task; Console.WriteLine("Press any key to exit"); Console.ReadLine(); } } 

要解决此问题,请添加等待SomeTask(); 调用,以便程序等待异步SomeTask()完成。 您还应该将SomeTask()的返回类型从void更改为Task。

 class Program { static void Main(string[] args) { await SomeTask(); } public static async Task SomeTask() { Task task = Task.Run(() => { System.Threading.Thread.Sleep(20000); Console.WriteLine("Task Completed!"); }); await task; Console.WriteLine("Press any key to exit"); Console.ReadLine(); } }