TaskCreationOptions 是向 TaskScheduler 传递调度偏好的提示枚举,除 AttachedToParent 必被遵守外,其余选项如 LongRunning(启用独占线程防池阻塞)、PreferFairness(倾向全局队列)、DenyChildAttach(拒绝子任务附加)、HideScheduler(禁用调度器继承)均可能被忽略。

TaskCreationOptions 是给 Task 调度器的“建议纸”,不是命令书
它本质是一组 TaskCreationOptions 枚举值,用于向 TaskScheduler 传递调度偏好。但要注意:**绝大多数选项只是提示(hint),调度器可以忽略**——除了 AttachedToParent,这个一定会被遵守,因为它不依赖调度器逻辑,而是由 Task 运行时直接处理父子关系。
-
LongRunning:提示“这活儿要干很久”,调度器大概率会开一个**全新线程(非线程池线程)**来跑,避免卡住线程池 -
PreferFairness:让任务尽量进全局队列,减少本地队列饥饿,但实际公平性取决于当前TaskScheduler实现 -
DenyChildAttach:父任务主动“拒收”子任务的AttachedToParent请求,子任务自动降级为分离任务 -
HideScheduler:子任务不继承父任务的TaskScheduler,强制用TaskScheduler.Default
什么时候必须用 AttachedToParent?
当你需要父任务 Wait() 或 await 时**自动等待所有子任务完成**,而不是手动 Task.WaitAll(...),就必须加 AttachedToParent。
var parent = new Task(() =>
{
var child1 = new Task(() => Thread.Sleep(100), TaskCreationOptions.AttachedToParent);
var child2 = new Task(() => Thread.Sleep(200), TaskCreationOptions.AttachedToParent);
child1.Start();
child2.Start();
});
parent.Start();
parent.Wait(); // ✅ 这里会等 child1 + child2 都结束才返回
漏掉 AttachedToParent?parent.Wait() 立刻返回,子任务可能还在后台跑——这是最常见的“以为等了其实没等” bug。
LongRunning 不是“性能优化开关”,而是资源隔离手段
别因为名字带 “Long” 就随便加。它的真实作用是:**防止长时间阻塞操作污染线程池**。
- 适用场景:
while(true) { ReadSensor(); Thread.Sleep(500); }类监控循环、同步 I/O 等待、或任何 > 1 秒且无法异步化的操作 - 反模式:用它包装一个
await HttpClient.GetAsync()—— 这是异步的,不该占专用线程 - 副作用:每个
LongRunning任务都新建线程,开多了会触发ThreadAbortException或内存压力
TaskFactory.CreationOptions 是“默认选项批发商”
如果你反复创建一堆行为一致的任务(比如全是 LongRunning + AttachedToParent),别每次都传参数,直接配工厂:
var factory = new TaskFactory(TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent); var t = factory.StartNew(() => DoWork()); // 自动带上两个 flag
注意:TaskFactory.CreationOptions 是只读属性,你只能在构造时指定;它不会影响已存在的任务,也不会覆盖你显式传入的 creationOptions 参数(后者优先级更高)。
最容易被忽略的一点:所有这些选项,只有在任务**真正被调度执行时**才起作用——如果任务还没 Start() 或被 await 挂起,它们只是静静躺在对象里,毫无意义。










