Task.WhenAny处理动态列表:添加元素后能否正常工作?
Task.WhenAny与动态修改任务列表的行为解析
结论先行:你的MakeLunch方法不会返回/完成,因为Task.WhenAny不会感知到调用之后对任务列表的修改。
核心原理拆解
Task.WhenAny(IEnumerable<Task>)的工作逻辑很直接:当你调用它的瞬间,它会一次性枚举并锁定传入的任务集合中的所有任务实例。之后不管你怎么修改原集合(添加、删除任务),都不会影响它的等待逻辑——它只会盯着最初捕获到的那些任务,直到其中任意一个完成。
结合你的代码分析
我们一步步看你的场景:
- 在
MakeLunch里,你创建了两个(理论上)永远不会完成的任务,把它们加入lunchTasks列表,然后调用await Task.WhenAny(lunchTasks)。此时Task.WhenAny已经“记住”了列表里的这两个任务,开始等待它们中的任意一个结束。 - 之后执行
CleanUp方法,往lunchTasks里添加了一个已完成的cleanUp任务。但这个新任务不在Task.WhenAny最初捕获的任务集合里,所以它完全不会被这个等待操作考虑。
因为那两个初始任务永远不会完成,MakeLunch里的await会一直挂起,方法永远不会返回。
额外注意点
顺便提一句:你的示例里Task.Delay(-1)会直接抛出ArgumentOutOfRangeException(因为Delay的参数不能是负数),如果是想模拟无限等待的任务,你可以用new TaskCompletionSource().Task来创建一个永远不会完成的任务实例。
如果你的需求是要支持动态添加任务并让等待逻辑感知到新任务,那你需要换一种实现方式——比如维护一个List<Task>,每次添加新任务后重新调用Task.WhenAny,或者使用TaskCompletionSource来手动触发完成信号,也可以借助Channel这类工具来管理动态任务流。
内容的提问来源于stack exchange,提问作者Kelvin Tam
相关产品推荐
相关产品推荐

