c# TaskCreationOptions 枚举有什么用

来源:这里教程网 时间:2026-02-21 17:39:04 作者:

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
挂起,它们只是静静躺在对象里,毫无意义。

相关推荐