C#多线程Task.Run和Task.Factory.StartNew

在使用多线程调用时,往往分不清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);

比如上面的案例,线程一直会运行下去,不用等待什么时候结束,不会卡系统。

还有个区别是最关键的参数不同
Task.Run 传入了TaskCreationOptions.DenyChildAttach,这可以在.NET源码中查看。如下开源代码:
  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/