运行或设置进程的低优先级

3

我想把一个进程设置为低优先级,但是在ProcessPriorityClass中没有选项可以把它设置为低优先级。但是如果我在任务管理器中手动将进程优先级设置为低,那么如何做呢?下面的代码是我用来将进程设置为低于正常优先级的。

Dim s As New Process
s.StartInfo.FileName = "D:\myapp.exe"
s.Start()
s.PriorityClass = ProcessPriorityClass.BelowNormal

任务管理器显示6个优先级选项。ProcessPriorityClass有6个枚举值。这不是巧合。当然,任务管理器不会使用单词“空闲”,那会让我妈妈大惑不解。 - Hans Passant
@HansPassant,那么ProcessPriorityClass.Idle和任务管理器中的Low是一样的吗? - IT researcher
1
我不明白为什么你需要问。你使用它时发生了什么?任务管理器告诉了你什么?不要编写你无法理解的代码。 - Hans Passant
1
你如果正在尝试处理进程,为什么还要使用任务管理器呢?有更好的工具可用;可以讨论ProcessHackerProcessExplorer的优缺点(我更喜欢前者,但后者在某些方面胜出),但与任何一个相比,任务管理器都非常有限。 - Jon Hanna
2个回答

18

“Low”值不存在,尽管有一个被默认任务管理器称为“Low”的ProcessPriorityClass.Idle(大多数其他任务管理器如ProcessHacker或ProcessExplorer将其称为“Idle”,如果你想要玩弄进程,你应该获取一个像ProcessHacker这样的体面任务管理器替代品,而不是针对非技术用户的内置应用程序)。

对我来说,将一个进程设置为ProcessPriorityClass.Idle没有问题。

但请注意:更改进程的优先级类通常是一个坏主意,特别是更改到idle,并且是从进程外部进行操作(至少从内部你可以决定为某些任务提高优先级,然后再将其设置回来)。

将优先级设置得太低可能会导致恶心的死锁,如果进程以不可共享的方式获得任何资源,因为当任何较高优先级的进程需要时间片时,它将无法运行(特别是在具有少量核心的机器上,因为同时可用的时间片较少),因此如果较高优先级的进程也需要一个资源,就会一直等待它,因为较低优先级的进程没有机会运行。

最终,Windows(虽然不是某些早期版本)将通过临时提高等待运行的较低优先级进程中的所有线程,使它们高于ProcessPriorityClass.High进程中的ThreadPriority.Highest线程,并逐渐让它们降低到较低的优先级,在那时问题再次发生。

这可能与你想要发生的相反。

而且,因为它对少量核心的机器特别残酷,如果你的开发装备很强大,你可能会出现在你的机器上一切正常的情况下,然后用户在机器性能较弱的情况下会发现一切都变得非常缓慢。

默认情况下,只有一些中断和“System Idle Process”(它是一个特殊情况)在空闲时运行,这是有很好的理由的。

但是,如果你确定自己知道自己在做什么(或者确实在进行实验),那么s.PriorityClass = ProcessPriorityClass.Idle就是你想要的。

编辑:关于优先级的更多信息:

给定线程具有相对于进程中其他线程的优先级,给定进程相对于系统上其他进程的优先级。

线程相对于系统上所有其他线程的优先级,取决于这两者,如下表所示:

       Thread: | Idle | Lowest | Below  | Normal | Above  | Highest | Time-Critical
               |      |        | Normal |        | Normal |         | 
---------------+------+--------+--------+--------+--------+---------+--------------
Idle Process   |  1   |   2    |   3    |   4    |   5    |    6    |     15
Below-Normal   |  1   |   4    |   5    |   6    |   7    |    8    |     15
Normal Process |  1   |   6    |   7    |   8    |   9    |   10    |     15
Above-Normal   |  1   |   8    |   9    |  10    |  11    |   12    |     15
High Process   |  1   |  11    |  12    |  13    |  14    |   15    |     15
Realtime       | 16   |  22    |  23    |  24    |  25    |   26    |     31
现在,任何一台计算机都将拥有X个核心,今天常见的值为1、2、4、8或16。每个核心每次只能运行一个线程。
如果要运行的线程比核心多,则调度如下:
1. 从现有的最高优先级线程开始。在它们之间共享核心。 2. 如果线程数超过了核心数,则在它们之间轮流分配核心,以使该优先级的所有线程均获得平等份额。 3. 如果还有剩余的核心,则对下一个最高优先级的线程执行相同操作,依此类推。
因此,如果有4个核心,并且我们有3个优先级为8的线程(例如普通进程中的普通线程)、2个优先级为10的线程(例如正常进程中的以上正常线程)和3个优先级为6的线程(空闲进程中的最高优先级线程),并且它们都准备好运行,则:
1. 2个优先级为10的线程始终会在核心上获得时间片。 2. 剩余的2个核心将在3个普通/正常线程之间进行时间共享。 3. 3个优先级为6的线程将没有运行的机会。
这对这3个线程来说很糟糕,但对整个系统来说应该是有益的,因为这3个线程应该只用于那些非常低优先级的事情,我们完全可以接受它们不运行。
这些数字还以以下方式提高:
1. 如果前台增强开启(桌面上是正常的,但服务器上不是),如果普通进程拥有前台窗口,则其优先级高于没有拥有前台窗口的正常进程。 2. 当一个窗口接收到鼠标、键盘或定时器输入,或来自另一个窗口的消息时,它所在的进程将获得临时提升。 3. 如果一个线程正在等待某些内容,而这些内容已经准备好了,它会获得提升。 4. 如果一个线程长时间准备就绪而没有运行,它可能会随机获得大幅提升。
前三个应该是常识,在这里不再赘述。
第四个引入了一个轻微的问题,以解决一个严重的问题:如果线程A需要低优先级线程B的资源,并且只有一个可用的核心,那么它们将死锁,因为线程B不会获得时间片,因此它不会释放资源,所以线程A会一直尝试获取资源,它不会结束,因此线程B不会获得时间片......
因此,操作系统将提升线程B的优先级为临时超高优先级,并且线程A一段时间内不会得到机会竞争资源。由于这种死锁的初始减速和这种暂时提高优先级所带来的影响,整个系统比应该慢得多(拥有一个多核心系统的实际优势不仅在于它能让很多繁忙的进程更好地协同工作,而是使这种情况发生的可能性小得多)。所有这一切的结果是,99%的时间,线程的最佳优先级是正常的,进程的最佳优先级也是正常的。
空闲/低应该为那些不重要到我们真的不在乎它们是否有机会做某事的进程保留。屏幕保护程序确实是一个例子,因为如果屏幕保护程序永远没有机会运行,它可能就不应该;没人会花大量钱购买最先进的计算机只是为了看飞行烤面包(虽然在20世纪90年代,人们可能会想知道)。
非正常优先级的好例子: “不要这样做”的问题在于,它总是不完整的;有很多事情,其中“不要这样做”通常是最好的建议(例如,干扰GC将是另一个例子),但是如果不理解例外情况,就无法真正领悟“不要这样做”的优点。实际上,除非涵盖了例外情况,否则它并不是好建议,而只是教条主义。因此,值得考虑高和低优先级的好例子以及它们中哪些可以解决所涉及的问题。
用于实时处理实时媒体。 如果您正在处理实时音乐或视频,并需要专业输出(您实际上正在录制或传输此内容给其他人,而不仅仅是在自己的计算机上观看它),那么最好在运行最高优先级的线程中进行此操作-也许设置进程为实时。这会对整个系统造成惩罚,但是那时候该机器上最重要的是处理媒体的进程,而考虑到媒体流遇到故障和某些严重问题可能发生在系统上之间的选择,您宁愿让严重问题发生在系统上,然后稍后再处理它们。所有“与其他进程友好相处”的正常概念都不起作用,实际上在*nix系统上,为这种目的经常使用针对可预测时间进行优化的实时内核,代价是并发性能不佳(尽管所有其他细节也将有所不同,我只是解释了上面的Windows方式)。
.NET中的Finalizer线程 .NET中的finaliser线程以高优先级运行。大多数情况下,此线程无事可做,因此处于非活动状态。当它确实需要做一些事情(finalisation队列不为空)时,无论有多少其他线程正在运行,它都至关重要。以下两点值得注意: 1.任何良好编写的finaliser都应该执行得很快,因此处理所有finaliser的总时间应该很短。 (在某些情况下,如果需要时间较长,则可能会放弃finalisation)。 2.任何良好编写的finaliser都不应干扰其他线程,因此处理所有finalisers也不应干扰其他线程。
这两个事实对于最小化高于正常优先级线程的缺点非常重要,因为它们意味着它不会陷入优先级倒置问题,并且大多数时间都不运行,因此不会与其他线程竞争。

系统空闲进程

在空闲状态下运行一个特殊的进程有两个目的。第一个是由于始终有一个在空闲中运行的线程,每个核心都有一个相应的线程,因此调度程序不需要处理没有可运行线程的情况,因为总是有这样的一个线程,上述逻辑将在没有其他线程时运行其中之一。

第二个目的是这些线程可以调用核心具备的任何省电或低频能力,因为如果它们运行一段时间,则按定义CPU不需要,并且应处于低功耗状态。

重要的是,该进程永远不会获得任何其他进程可能需要的非共享资源,因此它永远不会引起优先级反转问题。

在这里,我们可以看到该进程的目的就是尽可能不让其运行,只要有任何其他线程有任务要执行。

(它还为我们提供了一个很好的低优先级衡量标准。如果它与存在仅仅用于将CPU置于低功耗状态的线程竞争时,则不应具有低优先级。)


在阅读了http://msdn.microsoft.com/en-us/library/system.diagnostics.processpriorityclass(v=vs.110).aspx之后,我有些疑虑。其中提到“Idle”指的是此进程的线程仅在系统空闲时(如屏幕保护程序)运行。因此,我认为它可能与“Low”不同。 - IT researcher
从idle可以合理使用的角度来看,那是正确的。我会在答案中再补充一点。 - Jon Hanna
线程优先级的解释非常有趣。根据此文档所述,您的表格中存在一个错误:正常进程中的低于正常优先级的线程应具有优先级值7而不是6。 - Luca Cremonesi
@LucaCremonesi 是的,那只是个打字错误。谢谢。 - Jon Hanna
@JonHanna,根据你的回答方式,我猜你一定是一位教师。如果你不是,那么对于你的潜在学生和社会来说,这是一个巨大的浪费...绝对精彩的解释! - yanivps

2

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