26

在 Web 和 Stack Overflow 上有很多地方不鼓励更改ThreadPool线程或 TPL Task的优先级。尤其:

“您无法控制线程池线程的状态和优先级。”
“运行时管理线程池。你无法控制线程的调度,也无法更改线程的优先级。”

“你不应该改变 PoolThread 的文化或优先级或......。就像你不油漆或重新装饰一辆出租汽车一样。”

“有几种情况适合创建和管理自己的线程而不是使用线程池线程:(例如......)您需要一个线程具有特定的优先级。”

“ThreadPool 中的每个线程都以默认优先级运行,更改 ThreadPriority 的代码无效。”

但是,这样做很简单,并且调试器显示更改似乎确实存在(只要可以读回该值)。

Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;

那么问题来了,这个特定禁忌的具体原因是什么?

我的怀疑:这样做会扰乱池的微妙负载平衡假设。但这并不能解释为什么有些消息来源说你不能改变它。

4

6 回答 6

22

线程池,尤其是 .NET 4.0 线程池,有很多花招,是一个相当复杂的系统。加上任务和任务调度器,偷工减料和其他各种事情,现实是你不知道发生了什么。线程池可能会注意到您的任务正在等待 I/O,并决定在您的任务上安排一些快速的事情或暂停您的线程以运行更高优先级的事情。您的线程可能以某种方式依赖于更高优先级的线程(您可能知道也可能不知道)并最终导致死锁。您的线程可能会以某种异常方式死亡并且无法恢复优先级。

如果你有一个长时间运行的任务,你认为你的线程最好有一个较低的优先级,那么线程池可能不适合你。虽然算法在 .NET 4.0 中得到了改进,但它仍然最适合用于创建新线程的成本与任务长度不成比例的短期任务。如果您的任务运行时间超过一两秒,那么创建新线程的成本是微不足道的(尽管管理可能很烦人)。

于 2011-04-08T01:22:07.843 回答
9

我已经对减小大小的线程池进行了一些实验,这似乎表明一旦返回池,线程的优先级就会重置为正常。这个关于线程的资源似乎证实了这一点。所以即使你这样做,效果似乎也很有限。

于 2011-05-13T00:05:00.210 回答
2

降低优先级也可能导致意想不到的后果。

想象一下,您在应用程序中安排了一项任务,但还调用了一个安排其他几个任务的库。假设您在应用程序任务运行时降低了线程优先级。然后,如果池没有产生很多线程,那么您可能会在 lib 中等待该低优先级任务完成的正常优先级任务,但是如果池的其余部分没有产生低优先级线程,则它可能不会获得太多 CPU 时间系统有许多要运行的正常优先级线程。

增加池线程的数量可以缓解这种情况,但代价是在堆栈上浪费更多内存并在上下文切换上花费更多 CPU 时间。

于 2011-12-19T17:37:47.517 回答
0

如果您真的愿意,您当然可以更改它,但考虑到线程池线程被重用,下一个运行的代码可能不会期望更改。

于 2011-04-08T01:11:54.727 回答
0

如果您确实更改了任何内容,请使用 try/finally 以确保将其保留为您找到的内容。

于 2011-04-08T09:07:15.150 回答
0

不鼓励这样做,特别是如果您要提高优先级,因为它会影响系统的整体性能。

不要提供过于复杂的答案,但总的来说,线程优先级是一个复杂的话题。例如,Windows 有 2 个相关的描述符:线程优先级和进程优先级。两者的范围从最低的空闲到最高的时间关键。当您启动一个新进程时,它被设置为默认值,中间范围(普通进程优先级和普通线程优先级)。

另外,线程优先级是相对的,这意味着即使在繁忙的系统中将线程的优先级设置为最高也不能确保它会“实时”运行。DotNET 对此不提供任何保证,Windows 也不提供任何保证。从中您可以看到为什么最好不要管线程池,因为 99.9% 的时间,它最了解 :)

综上所述,如果任务涉及长时间计算,则可以降低线程的优先级。这不会影响其他进程。

然而,提高优先级应该只针对需要快速反应且执行时间短的任务,因为这会对其他进程产生负面影响。

于 2011-05-13T00:49:20.377 回答