You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中Async和Await未返回预期结果的问题排查

问题描述

在C#的Main方法中调用了4个同步任务(Task1-Task4)和4个异步任务(Task5-Task8),同步任务执行正常,但异步任务仅启动却未完成。同步任务使用Task.Delay().Wait()实现延迟,异步任务通过async void结合Task.Run与Thread.Sleep实现,期望得到如下指定输出结果,询问导致异步任务无法完成的原因。

Main方法代码

public static void Main(string[] args)
{
   // Synchronous methods
   Task1();
   Task2();
   Task3();
   Task4();

   // Asynchronous methods
   Task5();
   Task6();
   Task7();
   Task8();
}

任务实现代码

public static void Task1()
{
   Console.WriteLine(DateTime.Now.ToLongTimeString() + " : " + "Started task 1...");
   Task.Delay(4000).Wait();
   Console.WriteLine(DateTime.Now.ToLongTimeString() + " : " + "Completed task 1!");
}

public static void Task2()
{
   Console.WriteLine(DateTime.Now.ToLongTimeString() + " : " + "Started task 2...");
   Task.Delay(2000).Wait();
   Console.WriteLine(DateTime.Now.ToLongTimeString() + " : " + "Completed task 2!");
}

public static void Task3()
{
   Console.WriteLine(DateTime.Now.ToLongTimeString() + " : " + "Started task 3...");
   Task.Delay(5000).Wait();
   Console.WriteLine(DateTime.Now.ToLongTimeString() + " : " + "Completed task 3!");
}

public static void Task4()
{
   Console.WriteLine(DateTime.Now.ToLongTimeString() + " : " + "Started task 4...");
   Task.Delay(1000).Wait();
   Console.WriteLine(DateTime.Now.ToLongTimeString() + " : " + "Completed task 4!");
}

public static async void Task5()
{
   await Task.Run(() =>
     {
        Console.WriteLine(DateTime.Now.ToLongTimeString() + " : " + "Started task 5...");
        Thread.Sleep(4000);
        Console.WriteLine(DateTime.Now.ToLongTimeString() + " : " + "Completed task 5!");
     });
}

public static async void Task6()
{
   await Task.Run(() =>
     {
        Console.WriteLine(DateTime.Now.ToLongTimeString() + " : " + "Started task 6...");
        Thread.Sleep(2000);
        Console.WriteLine(DateTime.Now.ToLongTimeString() + " : " + "Completed task 6!");
     });
}       

public static async void Task7()
{
   await Task.Run(() =>
     {
        Console.WriteLine(DateTime.Now.ToLongTimeString() + " : " + "Started task 7...");
        Thread.Sleep(5000);
        Console.WriteLine(DateTime.Now.ToLongTimeString() + " : " + "Completed task 7!");
     });
}

public static async void Task8()
{
   await Task.Run(() =>
     {
        Console.WriteLine(DateTime.Now.ToLongTimeString() + " : " + "Started task 8...");
        Thread.Sleep(1000);
        Console.WriteLine(DateTime.Now.ToLongTimeString() + " : " + "Completed task 8!");
     });
}

期望输出

11:25:26 AM : Started task 1...
11:25:30 AM : Completed task 1!
11:25:30 AM : Started task 2...
11:25:32 AM : Completed task 2!
11:25:32 AM : Started task 3...
11:25:37 AM : Completed task 3!
11:25:37 AM : Started task 4...
11:25:38 AM : Completed task 4!
------------------
11:25:38 AM : Task 5 starting...
11:25:38 AM : Task 6 starting...
11:25:38 AM : Task 7 starting...
11:25:38 AM : Task 8 starting...
11:25:39 AM : Task 8 completed!
11:25:40 AM : Task 6 completed!
11:25:42 AM : Task 5 completed!
11:25:43 AM : Task 7 completed!
原因分析
  • 程序进程提前终止:Main方法是同步执行逻辑,调用完所有同步任务和异步任务后会直接结束进程。异步任务(Task5-Task8)运行在后台线程中,进程结束时后台线程会被强制终止,导致异步任务还未完成就被截断。
  • async void的设计局限性:async void定义的异步方法无法被调用者追踪和等待,Main方法无法获取这些异步任务的完成状态,自然无法等待它们执行完毕。async void仅适用于UI事件处理等特殊场景,普通异步方法应使用async Task作为返回类型。
解决方案

步骤1:修改异步方法的返回类型

将所有async void方法改为async Task,让调用者可以获取任务对象并等待其完成:

public static async Task Task5()
{
   await Task.Run(() =>
     {
        Console.WriteLine(DateTime.Now.ToLongTimeString() + " : " + "Started task 5...");
        Thread.Sleep(4000);
        Console.WriteLine(DateTime.Now.ToLongTimeString() + " : " + "Completed task 5!");
     });
}

// Task6-Task8做同样修改,将async void替换为async Task

步骤2:修改Main方法以等待异步任务完成

从C# 7.1开始,Main方法可以定义为async Task类型,直接使用await等待所有异步任务完成:

public static async Task Main(string[] args)
{
   // 同步任务按顺序执行
   Task1();
   Task2();
   Task3();
   Task4();

   Console.WriteLine("------------------");

   // 启动所有异步任务并等待全部完成
   await Task.WhenAll(Task5(), Task6(), Task7(), Task8());
}

若使用低于C#7.1的版本,可在Main中调用Task.WhenAll(...).Wait()阻塞等待:

public static void Main(string[] args)
{
   Task1();
   Task2();
   Task3();
   Task4();

   Console.WriteLine("------------------");

   // 等待所有异步任务完成
   Task.WhenAll(Task5(), Task6(), Task7(), Task8()).Wait();
}

额外优化建议

  • 同步任务中的Task.Delay(xxx).Wait()是阻塞调用,会占用主线程,若无需严格同步执行,可改为异步方式提升程序响应性。
  • 异步任务中的Thread.Sleep(xxx)会阻塞线程池线程,建议替换为await Task.Delay(xxx),避免浪费线程资源:
public static async Task Task5()
{
   Console.WriteLine(DateTime.Now.ToLongTimeString() + " : " + "Started task 5...");
   await Task.Delay(4000); // 替换Thread.Sleep
   Console.WriteLine(DateTime.Now.ToLongTimeString() + " : " + "Completed task 5!");
}

内容的提问来源于stack exchange,提问作者Showyeab Ahmed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 23:03:15