旁注

旁注

Linux(尚未)遵循 POSIX.1 标准,该标准进程上的arenice会影响“进程中的所有系统范围线程”,因为根据pthreads(7) 文档“线程不共享共同的好值”。

然而,有时,renice与给定进程相关的“所有内容”可能会很方便(一个例子是 Apache 子进程及其所有线程)。所以,

  • 我怎样才能renice全部线程属于给定进程 ?
  • 我怎样才能renice全部子进程属于给定进程 ?

我正在寻找一个相当简单的解决方案。

我知道进程组有时可能会有所帮助,但是,它们并不总是符合我想要做的:它们可以包含更广泛或不同的流程集。

使用cgroup管理者systemd也可能会有所帮助,但即使我有兴趣听到它,我主要寻找一个“标准”解决方案。

编辑:另外,man (7) pthreads还说“进程中的所有线程都放置在同一个线程组中;线程组的所有成员共享相同的 PID”。那么,renice没有自己的 PID 的东西是否有可能呢?

答案1

您可以用来/proc/$PID/task查找给定进程的所有线程,因此您可以使用

$ ls /proc/$PID/task | xargs renice $PRIO

renice所有人线程属于给定的进程。

同样的方法/proc/$PID/task/$PID/children可以找到所有子进程(或者/proc/$PID/task/*/children如果你想要所有子进程全部的线程给定过程)。

$ cat /proc/$PID/task/$PID/children | xargs renice $PRIO
$ cat /proc/$PID/task/*/children | xargs renice $PRIO

答案2

查找所有 PIDrenice 递归地

我们需要获取所有进程(“正常”或“线程”)的 PI​​D,这些进程是待处理进程的后代(子进程或线程组中的进程)。这应该是递归的(考虑到孩子的孩子)。

安东·列昂季耶夫答案给出了这样做的提示:其中的所有文件夹名称/proc/$PID/task/都是线程的 PID,其中包含children列出潜在子进程的文件。

然而,它缺乏递归性,因此这里有一个快速而肮脏的 shell 脚本来查找它们:

#!/bin/sh
[ "$#" -eq 1 -a -d "/proc/$1/task" ] || exit 1

PID_LIST=
findpids() {
        for pid in /proc/$1/task/* ; do
                pid="$(basename "$pid")"
                PID_LIST="$PID_LIST$pid "
                for cpid in $(cat /proc/$1/task/$pid/children) ; do
                        findpids $cpid
                done
        done
}

findpids $1
echo $PID_LIST

如果进程 PID 1234 是您想要递归处理的进程,现在您可以执行以下操作:

renice -n 15 -p $(/path/to/findchildren.sh 1234)

旁注

价值好还是CPU 份额好?

请注意,现在,由于自动任务分组,特别是在使用时,好的值可能与“系统范围”不那么相关系统。请参见这个答案更多细节。

线程和进程的区别

笔记:这个答案准确地解释了 Linux 线程。

简而言之:内核只处理“可运行实体”,即可以跑步预定的。从内核角度来看,这些实体称为进程。线程只是一种与另一个进程共享(至少)内存空间和信号处理程序的进程。每个这样的进程都有一个系统范围内的唯一标识符:PID(进程ID)。

结果,你 renice每个“线程”都是单独的,因为它们确实有自己的自己的PID 1


1这个答案有关 PID (ProcessID) 和 TID 区别 (ThreadID) 的更多信息。

答案3

我们不应该混淆进程PID和线程ID,有时写为TID或在ps命令LPW中。该s命令具有显示线程的选项,您可以在top或下在htop线程之间切换并按H字母进行处理。正如@Totor之前所说,对于NPTL(内核> 2.6的当前实现),所有线程都具有相同的pid,但它们具有不同的tid。您可以通过以下方式显示进程的所有线程:

$ ps -Ljf <pid>

这些 tid 是 下目录的名称/proc/<pid>/task,即使雷尼斯(1)假设它的默认参数是一个 pid,当应用于 pid 时,它只对主线程进行调整(这是 linux 实现中的一个错误,如设置优先级(2)),它也可以应用于 tid 并重新调整线程。这就是为什么@Anton 的答案是有效的。

但大多数情况下,有一种更简单的方法可以实现所需的结果,所有这些线程共享相同的 pgid,即组领导者的 pid;您可以通过 pgid 发出以下命令来重新启动:

$ renice -g <pgid>

如果您不想重新启用依赖于同一组领导者的其他进程,则必须使用@Anton的配方:

$ renice <priority> $(ls -1 /proc/<pid>/task)

或者:

$renice <priority> $(ps --no-header -Lo tid <pid>)

您可能还想知道除了您想要重用的进程之外,同一组中还有哪些进程,即共享具有相同 pgid 的进程。您可以使用附注(1)ps不允许按组长选择进程,但您可以 grep aps来执行此操作。具有 pgid 的进程1908将由以下命令给出:

$ ps --no-header axo pid,pgid |sed -n '/^ *[0-9][0-9]*  *1908/s/[0-9][0-9]* *$//p'

或者如果您更喜欢 awk 而不是 sed:

$ ps --no-header axo pid,pgid|awk '{if ($2=="1908") print $1;}'

答案4

我想建议在使用 renice 时使用 -g(进程组)参数而不是 -p(进程 ID)。没有 bash-foo 也可以做同样的事情。

IE

(sudo) renice -n <NEW_PRIORITY> -g <MAIN_PROCESS_ID>

相关内容