如何让异步Action在ExecuteActivityAsync中完整同步执行?
问题解决思路及代码修改方案
问题根源
你当前代码的核心问题是使用了async void委托(将异步lambda赋值给Action类型)。async void属于异步编程中的“火并忘记”模式,Task.Run无法跟踪其完整的异步执行流程——当执行到第一个await时,Task.Run就会认为任务已完成,触发后续的ContinueWith逻辑,而实际后续的异步方法还在后台执行,这就导致了"Completed"提前输出。
修改方案
- 将委托类型从
Action改为Func<Task>,这样异步lambda会返回Task,其完整的异步执行流程可以被正确跟踪。 - 调整
ExecuteActivityAsync方法的参数类型,并移除ContinueWith,直接await异步委托的执行结果,确保所有异步步骤完成后再输出"Completed"。
修改后代码
Test方法修改
public async Task Test() { CancellationToken cancellationToken = default; // 替换Action为Func<Task>,让异步lambda返回可跟踪的Task Func<Task> taction = async () => { this.Insert(); await this.Method1(); await this.Method2(); await this.Method3(); await this.SaveChangesAsync(cancellationToken); }; await this.ExecuteActivityAsync(taction); }
ExecuteActivityAsync方法修改
private async Task ExecuteActivityAsync(Func<Task> act) { await semaphore.WaitAsync(); try { Console.WriteLine("StartExecution"); // 直接await异步委托,确保所有步骤执行完成 await act(); Console.WriteLine("Completed"); Console.WriteLine("EndExecution"); await Task.Delay(10000); } finally { semaphore.Release(); } }
若需保留Task.Run执行(可选)
如果需要将委托放在后台线程执行,可修改为如下形式:
private async Task ExecuteActivityAsync(Func<Task> act) { await semaphore.WaitAsync(); try { Console.WriteLine("StartExecution"); // 用Task.Run包装后await,确保后台线程的异步流程完成 await Task.Run(act); Console.WriteLine("Completed"); Console.WriteLine("EndExecution"); await Task.Delay(10000); } finally { semaphore.Release(); } }
修改后,控制台输出将完全符合你的预期顺序。
内容的提问来源于stack exchange,提问作者rebe21
相关产品推荐
相关产品推荐

