在使用多线程调用时,往往分不清Task.Run和Task.Factory.StartNew的使用场景,这篇文章介绍两者的背景以及两者的区别和应用。
背景
在.net 4中,Task. factory.startnew是调度新任务的主要方法。但是在使用时,你需要知道在何时使用那个重载、提供什么样的调度器等等,这使得Task. factory.startnew开发使用不够灵活方便。.
因此,在 .NET Framework 4.5 开发者预览版中,微软引入了新的 Task.Run 方法。这并不意味 Task.Factory.StartNew过时,而Task.Run简单地认为是一种使用 Task.Factory.StartNew 的快速方法,它无需更多引用,让开发者更快捷的使用多线程。底层上,Task.Run 实际上是按照与 Task.Factory.StartNew 相同的逻辑来实现的,只是将默认参数省略。当您将 Action 传递给 Task.Run 时
Task.Run(someAction);
这完全等同于:
Task.Factory.StartNew(someAction,
CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
通过这种方式,Task.Run 用于最常见的情况,即简单装载一些要在 ThreadPool 上处理的工作(TaskScheduler.Default 的目标)。这并不意味着 Task.Factory.StartNew 将不再被使用;还差得很远。Task.Factory.StartNew 仍然有许多重要(尽管更高级)的用途。Task.Run只是重载了Task.Factory.StartNew的轻形替代方案。
Run和StartNew区别
在最基本的使用上没有啥差别,都可以调用task,大家看看下面代码
Task.Factory.StartNew(() => { Console.WriteLine("任务1"); });
Task.Run(() => { Console.WriteLine("任务2"); })
Task.Factory.StartNew可以使用更多的参数,如果没有特别要求,推荐大家用Task.Run。
具体区别在哪呢?
Task.Factory.StartNew可以设置线程长时间运行,线程池就不需要等待回收这个线程。具体使用如下:
Task.Factory.StartNew(() =>
{
for (int i = 0; i < 1000000000; i++)
{
string run = "运行:"+i;
}
Console.WriteLine("正在运行的的线程" + Thread.CurrentThread.ManagedThreadId);
}, TaskCreationOptions.LongRunning);
比如上面的案例,线程一直会运行下去,不用等待什么时候结束,不会卡系统。
public static Task Run(Action action)//Task.run
{
return Task.InternalStartNew(null, action, null, default, TaskScheduler.Default,
TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None);
}
public Task StartNew(Action action)//Task.Factory.StartNew
{
Task? currTask = Task.InternalCurrent;
return Task.InternalStartNew(currTask, action, null, m_defaultCancellationToken, GetDefaultScheduler(currTask),
m_defaultCreationOptions, InternalTaskOptions.None);
}
那么DenyChildAttach是干啥的呢?查看官方文档的解释,DenyChildAttach 的作用是阻止子任务附加到其父任务。小编尝试对比两者父类代码的使用,由于时间关系未达到目的,感兴趣的朋友可以尝试一下。其它参数区别可以查官网。
其它还有啥区别呢,大家可以留言讨论。
参考:https://devblogs.microsoft.com/pfxteam/task-run-vs-task-factory-startnew/