代码死锁风险与async-all-the-way原则合规性问询
关于VehicleFactory代码的两个技术问题解答
代码示例
public record Vehicle( Axel FrontAxel, Axel RearAxel ) { } public record Axel( IList<Wheel> Wheels ) { } public record Wheel( float TirePressure ) { } public static class VehicleFactory { // async public static async Task<Vehicle> CreateAsync( int wheelsPerAxel ) { var frontAxelTask = CreateAxelAsync( wheelsPerAxel ); var rearAxelTask = CreateAxelAsync( wheelsPerAxel ); await Task.WhenAll( frontAxelTask, rearAxelTask ); return new Vehicle( frontAxelTask.Result, rearAxelTask.Result ); } // async private static async Task<Axel> CreateAxelAsync( int wheelsPerAxel ) { var wheelTasks = new Task<Wheel>[ wheelsPerAxel ]; for ( int i = 0; i < wheelsPerAxel; i++ ) { int wheelIndex = i; wheelTasks[ i ] = Task.Run( () => CreateWheel( wheelIndex ) ); } Wheel[] wheels = await Task.WhenAll( wheelTasks ); return new Axel( wheels ); } // sync private static Wheel CreateWheel( int wheelIndex ) { float tirePressure = CalculateTirePressure( wheelIndex ); return new Wheel( tirePressure ); } // sync private static float CalculateTirePressure( int wheelIndex ) { float tirePressure; // perform some CPU-bound processing and assign to tirePressure return tirePressure; } }
问题1:该代码是否存在死锁风险?
不存在死锁风险。原因如下:
- 死锁的常见触发场景是在持有同步上下文的线程中阻塞等待异步任务完成(比如UI线程直接调用
.Result/.Wait()),但这段代码中所有异步等待都使用await关键字,而非阻塞式调用。 CreateAsync方法中先通过await Task.WhenAll等待所有轴的创建任务完成,之后再访问Task.Result,此时任务已经处于完成状态,不会触发阻塞逻辑。CreateAxelAsync中用Task.Run将CPU密集型的同步方法CreateWheel调度到线程池执行,脱离了原调用上下文,进一步避免了上下文相关的死锁可能。
问题2:是否违反async-all-the-way原则?
不违反。async-all-the-way的核心要求是异步调用链中避免同步阻塞,而非强制所有底层方法必须是异步实现:
- 这段代码的整个调用链从
CreateAsync到CreateAxelAsync都使用async/await异步等待,没有出现.Result/.Wait()这类阻塞操作。 CreateWheel和CalculateTirePressure是CPU密集型的同步方法,用Task.Run包装是合理的——这是将同步CPU任务异步化的标准做法,目的是避免阻塞调用线程(比如UI线程或ASP.NET请求线程),符合异步编程的最佳实践。
内容的提问来源于stack exchange,提问作者arktos
相关产品推荐
相关产品推荐

