如何在C#中获取TPL任务线程的引用?

6
当我创建一个任务时,

Task task = Task.Factory.StartNew(() => someMethod(args));

在C# 4.0+中,如何获取此任务的线程引用?任务是否可能在创建任务的同一线程中执行或产生多个线程?更新:原因是我想在调试器中标识任务的线程(并为其指定名称),等等。创建的任务是否总是在与创建任务的线程不同的单独线程中执行?是一个、零还是多个线程?它在单个且相同的核心上执行吗?这很重要,因为例如,我可以将主线程设置为休眠,认为我正在冻结后台工作程序。更新:有用的答案:在使用Task.StartNew时指定线程名称

5
你永远不需要这样做。你试图解决什么问题? - SLaks
1
据我所知,你不能这样做。无法保证任务将生成一个新线程,它可以在创建它的同一线程上运行。此外,该任务(可能)可以在多个线程之间分割。但是我和@SLaks一样,对于这种方法总体上存在一些问题。 - Patryk Ćwiek
答案:(1)可以,但为什么呢?(2)是的,(3)是的。 - user7116
你考虑这样做的原因是什么?你的目标是什么?线程的数量和重用并不可从外部预测。此外,更多的线程并不一定意味着工作速度更快。例如,如果你只有一个单核 CPU 并且唯一要做的事情是计算,那么每个额外的线程都是资源的浪费。此外,生成线程需要时间和内存,有时这比使用多个 CPU 的好处更加昂贵。 - Boas Enkler
@ sixlettervariables,你能否将你的评论放在回答中,并标识出你回答的问题分别是(1)、(2)和(3)吗? - Fulproof
2
如果您为该线程分配一个名称,该名称将在任务的持续时间内保持不变。其他任务可能会共享相同的线程名称,这将会令人困惑。我希望有一种方法可以给任务命名。 - usr
3个回答

9
被创建的任务是否总是在与创建任务的线程不同的线程中执行?
不是,TPL能够确定在某些情况下任务可以在创建它的同一线程上执行,这要么是因为提供了相关的任务创建选项(或任务调度程序),要么是作为优化,因为调用线程没有其他事情可做。但您真的不需要担心这个问题;除非您明确指示,否则不会像TPL选择在该上下文中执行其代码那样阻止UI线程。就所有目的而言,您可以假设这永远不会发生(除非您强制发生),但在幕后,无需您意识到它,是的,它可能会发生。
是一个、零个还是多个线程?
默认情况下,任务在线程池中执行。线程池将根据其工作负载而变化,包含的线程数也会随之变化。它将从一个开始,但如果有足够的需求,它将增长,如果需求消失,则缩小。如果指定了LongRunning选项,则仅为该任务创建一个新线程。如果指定自定义TaskScheduler,则可以让它执行任何您想要的操作。
它是否在单个相同的核心上执行?
可能是,但不一定。
这很重要,例如,我可以使主线程休眠,以为我正在冻结后台工作线程。
使主线程休眠不会阻止后台工作线程工作。这就是创建后台工作线程的全部意义,两个任务不会相互阻止。请注意,如果后台工作线程尝试访问UI以报告进度或显示结果,并且UI被阻塞,则它们将在该点等待UI线程空闲。

1
+1,关于在调试器中查找任务的问题,我会指向Task.Id/Task.CurrentId(MSDN指出这是为调试器而设)和Parallel Tasks window - user7116

4

您可以使用:

System.Threading.Thread.CurrentThread

但正如评论中所说,使用TPL抽象线程,因此回到这个“低级别”可能表明设计不良。


3

Task.Factory.StartNew()方法将任务加入执行队列(参见此处)。实际执行任务的线程及其执行时间由指定的TaskScheduler决定(若未指定则使用当前TaskScheduler)。

在.Net 4中,默认的TaskScheduler使用ThreadPool来执行任务(参见此处),因此如果一个ThreadPool Thread排队了该任务,则有可能后续该线程也会执行它。

线程数取决于ThreadPool。

你应该不太关心任务在哪个核心上执行。

将任务加入执行队列时,很可能会在ThreadPool Thread上安排其执行,所以你不用担心误将主线程置于睡眠状态。


如果没有指定任务调度程序,则使用默认任务调度程序(使用线程池的那个),而不是当前任务调度程序。 - Servy
1
不是根据 MSDN 文档。它说调用 Factory.StartNew() 相当于创建一个 Task 并调用 Task.Start(),该方法使用当前线程。请参见我帖子中的链接。 - HasaniH

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