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

.NET Core异步多线程控制台应用Task.WhenAll后未输出控制台信息且应用提前关闭问题排查

问题分析与解决方案

你的核心问题是主线程提前退出,导致异步任务还没执行完毕,应用就被关闭了,所以Console.WriteLine("Finish running code")根本没机会执行。我们一步步拆解问题并修复:

问题1:主线程未等待异步任务完成

你的Main方法是void类型,调用异步方法时没有等待其完成:

  • host.RunAsync()是异步方法,但你没有await它,它会在后台启动主机,但主线程会继续往下走
  • RunTask是同步方法,里面调用了async Task类型的Execute,但同样没有等待Execute完成
  • 当Main方法执行完毕后,整个进程就会终止,所有未完成的异步任务都会被强制取消,这就是你看到application is shutting down的原因

问题2:不必要的Task.Run包裹异步方法

ProcessPendingRegistrationsAsync本身就是async Task方法,直接返回任务即可,不需要用Task.Run包裹——Task.Run在这里会创建一个嵌套任务,虽然最终也能执行,但属于多余的开销,还容易造成混淆。


修复后的代码示例

1. 修改Program.cs,让主线程等待异步任务完成

将Main改为async Task(.NET Core 3.0+支持异步入口方法),并等待所有任务执行完毕:

internal class Program { 
    // 改为异步入口方法,让主线程可以等待异步操作
    private static async Task Main(string[] args) { 
        var log4NetConfiguration = new Log4NetConfiguration(); 
        log4NetConfiguration.SetLog4NetConfiguration(); 
        var host = CreateHostDefaultBuilder(args).Build(); 

        // 启动主机并在后台运行
        var hostBackgroundTask = host.RunAsync();

        // 等待业务任务执行完成
        await RunTask(host.Services);

        // 任务完成后,停止主机并等待其关闭
        await host.StopAsync();
        await hostBackgroundTask;
    } 

    public static IHostBuilder CreateHostDefaultBuilder(string[] args) { 
        return Host.CreateDefaultBuilder() 
            .ConfigureAppConfiguration(app => { app.AddJsonFile("appsettings.json"); }) 
            .ConfigureServices((_, services) => { 
                services.ConfigureDAL().ConfigureBusiness().ConfigureConnectionHelper().ConfigureTimeOutSetting(); 
            }); 
    } 

    // 改为异步方法,等待TaskHelper的Execute完成
    public static async Task RunTask(IServiceProvider services) { 
        var taskHelper = services.GetService<TaskHelper>(); 
        if (taskHelper != null)
        {
            await taskHelper.Execute(true); 
        }
    } 
}

2. 修改TaskHelper.cs,去掉多余的Task.Run

public class TaskHelper
{
    private readonly IDRegistration _dRegistration;
    // 明确任务列表的类型
    private List<Task<List<RegistrationData>>> _processPendingRegistrationsTasks = new();

    // 依赖注入构造函数(确保你的服务已正确注册)
    public TaskHelper(IDRegistration dRegistration)
    {
        _dRegistration = dRegistration;
    }

    public async Task Execute(bool forceMode) { 
        var openPendingRegistrationsPerPages = _dRegistration.GetAllRegistrationsByStatusAndSubStatusPerPage(cachedByGuid[1], cachedByGuid[2]); 

        // 直接添加异步方法返回的Task,无需Task.Run
        foreach (var openPendingRegistrationsData in openPendingRegistrationsPerPages)
        {
            _processPendingRegistrationsTasks.Add(ProcessPendingRegistrationsAsync(openPendingRegistrationsData));
        }

        if (_processPendingRegistrationsTasks.Count > 0) { 
            await Task.WhenAll(_processPendingRegistrationsTasks); 
        } 

        // 现在这行代码会被正常执行
        Console.WriteLine("Finish running code"); 
    } 

    private async Task<List<RegistrationData>> ProcessPendingRegistrationsAsync(List<RegistrationData> registrations) { 
        // 在这里添加你的实际异步处理逻辑(比如数据库操作、API调用等)
        // 示例:await _someService.ProcessRegistrationAsync(registrations);
        return registrations; 
    } 
}

修复说明

  1. 异步入口方法:async Task Main让主线程能够等待所有异步操作完成,不会提前终止进程。
  2. 等待主机与业务任务:先启动主机(保证服务可用),再执行业务任务,任务完成后再关闭主机,确保整个流程完整。
  3. 移除多余的Task.Run:异步方法本身返回Task,直接加入任务列表即可,Task.WhenAll会正确等待所有任务执行完毕。

内容的提问来源于stack exchange,提问作者mohammad hamid

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 17:27:30