每个新的System.Threading.Tasks.Task()都会创建一个新的线程吗?

4

我刚尝试使用Task对象,使我的时间操作在单独的通道中运行。但我想知道Task(()=>{...})是否类似于创建new Thread(new ThreadStart(()=>{....}))


任务使用线程池,而不是线程。 - Rangesh
3个回答

3

简短回答:不是。任务是通过线程池执行的。这里有一篇关于此的博客:Threads vs. Tasks:任务不会创建自己的操作系统线程。而是由TaskScheduler执行任务;默认调度程序仅在ThreadPool上运行。


你的意思是说,当我创建一个新任务时,它会从线程池中实例化/创建/加载一个新线程? - BreakHead
如果线程池中有可用的空闲线程,它将使用该线程。如果线程池中当前没有任何空闲线程,则将创建一个新线程。当线程池中有一些空闲线程时,其中一些线程将被停止。(这有点简化,但你明白了吧。) - Matthew Watson
@Matt 谢谢,最后一个问题,这个线程池是由 .Net 自己维护的吗? - BreakHead
这只是众多可能性之一,但绝不是唯一的。即使使用“Task”构造函数创建的任务也不一定在线程池上执行。 - Servy

3
一个 Task 表示在未来某个时间完成工作的承诺
有几种创建 Task 的选项:
  1. 使用没有任何标志的 Task.RunTask.Factory.StartNew - 这将在 .NET 线程池上排队工作。

  2. 使用 Task.Factory.StartNew 并指定 TaskCreationOptions.LongRunning - 这将通知 TaskScheduler 使用新线程而不是 ThreadPool 线程。

  3. 使用 C#-5 的 async-await 特性,也称为 Promise Tasks。当您 await 返回 TaskTask<T> 的方法时,它们可能不使用任何线程机制,无论是 ThreadPool 还是 new Thread 来执行其工作,因为它们可能使用纯异步 API,这意味着它们将继续在执行它们的线程上执行,并且一旦遇到第一个 await 关键字,就会将控制权返回给调用方法。

  4. 感谢 Servy 提供的信息。另一种执行选项是创建自定义 TaskScheduler 并将其传递给 Task.Factory.StartNew。自定义 TaskScheduler 将为您提供对任务执行的精细控制。

所有这些选项都表明,Task 只是一个承诺,而有许多形式可以实现该承诺。线程只是达到目的的手段,而 Task 则是我们想要完成的工作单位。

1
针对您提到的第三点,确实可以创建代表该点的任务,但它们并不是通过使用await来创建的。任何在await之后运行的代码都是在某个实际线程上运行的。await只是一个工具,让您在任务完成时运行一些代码;被等待的任务可能涉及实际线程的使用,也可能不涉及。此外,在使用Run时,除了1和2之外,还有其他选项可供选择。 - Servy
@Servy 我已经编辑了第3点,以澄清我的意思。至于其他选项,您能详细解释我错过了什么吗? - Yuval Itzchakov
1
你错过了一个自定义任务调度程序。 - Servy

2
可能。这取决于情况。
默认情况下,使用Task.Run、Task.Factory.StartNew或Task构造函数创建的Task对象将使用默认的TaskScheduler,该调度程序将安排委托在线程池中运行。
可以使用非默认的TaskScheduler来安排任务在您定义的任何线程上运行。您可以定义它在UI线程、自己的新线程、除.NET线程池之外的线程池中运行,根本不运行或其他任何您想要的方式。
您可以使用TaskCompletionSource创建一个Task,在这种情况下根本不需要存在任何线程。Task甚至不需要表示委托的完成。它可以表示任何在未来某个时间完成的操作,可能带有结果。它可能涉及在线程上运行的一些代码,也可能表示固有的异步操作,例如IO、用户行为、事件触发、各种其他任务的组合或任何其他您想要创建的内容。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接