Task.Factory.StartNew
和 Task.Run
都是用来启动新任务的,但它们有一些关键区别,我们来一条一条讲清楚(配例子 + 结论)。
🆚 1. 语法和使用目的
对比项 | Task.Run |
Task.Factory.StartNew |
---|---|---|
用途 | 简化写法,用于启动"后台任务" | 更底层、更灵活,用于高阶配置 |
返回值 | Task |
Task , Task<TResult> ,可高度配置 |
引入版本 | .NET 4.5 起 | .NET 4.0 起 |
✅ 示例对比:
Task.Run
(推荐现代用法):
csharp
Task.Run(() => {
// 简洁:默认在线程池启动
});
Task.Factory.StartNew
(配置能力强):
csharp
Task.Factory.StartNew(() => {
// 可以指定选项(TaskCreationOptions、调度器等)
}, CancellationToken.None,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);
🆚 2. 默认行为区别(重点⚠️)
项目 | Task.Run |
Task.Factory.StartNew |
---|---|---|
使用线程池 | ✅ 是 | ✅ 是 |
支持 async/await 正确传播上下文 | ✅ 是 | ⚠️ 否(默认不会) |
默认调度器 | TaskScheduler.Default |
调用线程的调度器(可能不同) |
异步嵌套行为 | ✅ 自动 unwrap | ⚠️ 不自动 unwrap(会返回 Task<Task> ) |
❗ async lambda 注意区别:
csharp
// 正确 await:Task.Run
await Task.Run(async () => {
await Task.Delay(1000);
});
// ⚠️ 这里返回的是 Task<Task>(需要手动 Unwrap 或 await 两次)
Task.Factory.StartNew(async () => {
await Task.Delay(1000);
});
🆚 3. 适用场景
场景 | 推荐 |
---|---|
启动后台任务,异步执行工作 | ✅ Task.Run |
需要高级配置(如 LongRunning、专用 TaskScheduler) | ✅ Task.Factory.StartNew |
和 async/await 配合 | ✅ Task.Run 更安全 |
想控制是否使用线程池、任务选项、调度器等 | ✅ StartNew 有更高自由度 |
✅ 总结推荐
- ✅ 日常写 async 或后台处理?用
Task.Run
,安全简洁。 - 🔧 有特殊需求(如长时间任务、不走线程池、UI 调度器)?用
Task.Factory.StartNew
。
🚨 最后提醒(常见坑):
csharp
// ⚠️ 容易犯错:
Task.Factory.StartNew(async () => {
await Task.Delay(1000);
}); // 返回 Task<Task>,容易误用!
👇正确用法:
csharp
await Task.Run(async () => {
await Task.Delay(1000);
});