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
递归地
我们需要获取所有进程(“正常”或“线程”)的 PID,这些进程是待处理进程的后代(子进程或线程组中的进程)。这应该是递归的(考虑到孩子的孩子)。
安东·列昂季耶夫答案给出了这样做的提示:其中的所有文件夹名称/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>