.net Task底层原理探究
- 自从
.Net Framework 4.0增加了Task之后,日常开发中的多线程需求,几乎都会用Task功能,那么Task究竟是什么?底层运行原理是什么?今天就来深挖一下。 - 整个
Task.cs文件,有7000多行代码,可见其复杂性
创建Task的几种方式
-
直接创建
Taskvar task = new Task(()=>{});
-
Task.Run(()=>{})- 其实就是 直接创建Task,然后调用
ScheduleAndStart方法,采用默认的TaskScheduler也就是在线程池中运行。
- 其实就是 直接创建Task,然后调用
-
Task.Factory.StartNew(()=>{}) -
Paraller.For(0, 100, (i) => {}) -
Paraller.Invoke(()=>{}, ()=>{}) -
Enumerable.Range(0, 1).AsParaller().ForAll(i => {})
直接创建Task
var task = new Task(()=>{});
task.Start();
- 日常开发中很少用到这种方式,一般使用
Task.Run和Task.Factory.StartNew,但其实后两种方式都是对于直接创建Task的封装,直接创建Task有以下两种好处- 可以分离创建任务和启动任务,后两种方式都是创建任务后直接启动
- 控制性更强,自定义化更高,你可以自行选择传入
TaskScheduler和TaskCreationOptions参数。(更推荐使用Task.Factory.StartNew)
Task.Run
- 底层是调用
InternalStartNew(action, TaskScheduler.Default, TaskCreationOptions.DenyChildAttach)TaskScheduler.Default默认为ThreadPoolTaskScheduler
- 其实就是 直接创建Task,然后调用
ScheduleAndStart方法,采用默认的TaskScheduler也就是在线程池中运行。
Task.StartNew
- 和
Task.Run类似,底层也是调用InternalStartNew,但是可以自行传入TaskScheduler和TaskCreationOptions参数
TaskCreationOptions 的作用
-
使用场景举例:轮询线程,一般它的生命周期和应用程序的生命周期相同,不合适使用线程池线程,这种场景下创建Task的时候传入参数
TaskCreationOptions.LongRunning就会直接new Thread,而不是使用线程池线程Task.Factory.StartNew(Polling, TaskCreationOptions.LongRunning)
-
TaskCreationOptions还有其他的一些不常用的值,这里就不作深入了解。 -
具体代码可以看下方的
ThreadPoolTaskScheduler.cs
自定义 TaskScheduler
-
创建Task的两个重要参数:
TaskSchedulerandTaskCreationOptions,其中TaskCreationOptions上面已经讲过,接下来再来研究下TaskScheduler -
可以理解为它的默认参数是
TaskScheduler.Default。 -
接下来自定义
TaskScheduler,让创建的线程使用new Thread方式
Task.Factory.StartNew(() =>
{
}, new CancellationToken(), TaskCreationOptions.LongRunning, new CustomTaskScheduler());
public class CustomTaskScheduler : TaskScheduler
{
protected override IEnumerable<Task> GetScheduledTasks()
{
return null;
}
protected override void QueueTask(Task task)
{
var thread = new Thread(() =>
{
TryExecuteTask(task);
});
thread.Start();
}
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
throw new NotImplementedException();
}
}
Task简化版源码
- Task.cs
public class Task
{
private TaskScheduler m_taskScheduler; // The task scheduler this task runs under.
private Delegate? m_action;
private object? m_stateObject; // A state object that can be optionally supplied, passed to action.
internal Task(Delegate action, object? stateObj, TaskScheduler taskScheduler, TaskCreationOptions taskCreationOptions)
{
m_action = action;
m_taskScheduler = taskScheduler;
}
public void Start()
{
Start(TaskScheduler.Current);
}
public void Start(TaskScheduler scheduler)
{
m_taskScheduler = scheduler;
ScheduleAndStart(true);
}
public void ScheduleAndStart(bool needsProtection)
{
m_taskScheduler.InternalQueueTask(this);
}
public static Task Run(Action action)
{
// TaskScheduler.Default is ThreadPoolTaskScheduler
return InternalStartNew(action, TaskScheduler.Default, TaskCreationOptions.DenyChildAttach);
}
internal static Task InternalStartNew(Delegate action, TaskScheduler scheduler, TaskCreationOptions options)
{
Task t = new Task(action, null, scheduler, options);
t.ScheduleAndStart(false);
return t;
}
}
- ThreadPoolTaskScheduler.cs
public class ThreadPoolTaskScheduler: TaskScheduler
{
private static readonly ParameterizedThreadStart s_longRunningThreadWork = static s =>
{
((Task)s).ExecuteEntryUnsafe(threadPoolThread: null);
};
internal override void QueueTask(Task task)
{
TaskCreationOptions options = task.Options;
// 如果是长期运行,不进线程池,直接创建Thread并启动
if ( (options & TaskCreationOptions.LongRunning) != 0)
{
new Thread(s_longRunningThreadWork){
IsBackground = true,
Name = ".NET Long Running Task"
}.UnsafeStart(task);
}
// 进入线程池
else
{
// 如果是 PreferFairness 就是 Local,否则就是Global
ThreadPool.UnsafeQueueUserWorkItemInternal(task, (options & TaskCreationOptions.PreferFairness) == 0);
}
}
}
浙公网安备 33010602011771号