Tot*_*tor 32 linux process nice thread
Linux没有(还)遵循POSIX.1标准,它说的是一renice对过程的影响“的过程中所有的系统范围线程”,因为根据并行线程(7)文档“线程不共用一个很好的价值。”
然而,有时,renice与给定进程相关的“一切”可能很方便(一个例子是 Apache 子进程及其所有线程)。所以,
renice所有线程?renice所有子进程?我正在寻找一个相当简单的解决方案。
我知道流程组有时会有所帮助,但是,它们并不总是符合我想要做的:它们可以包含更广泛或不同的流程集。
使用cgroupmanaged bysystemd也可能会有所帮助,但即使我有兴趣了解它,我也主要寻找“标准”解决方案。
编辑:还有,man (7) pthreads说“一个进程中的所有线程都放在同一个线程组中;线程组的所有成员共享同一个 PID”。那么,甚至有可能renice没有自己的 PID 吗?
小智 29
您可以使用/proc/$PID/task来查找给定进程的所有线程,因此您可以使用
$ ls /proc/$PID/task | xargs renice $PRIO
Run Code Online (Sandbox Code Playgroud)
对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
Run Code Online (Sandbox Code Playgroud)
Tot*_*tor 13
renice 我们需要获取所有进程(“正常”或“线程”)的 PID,这些进程是待处理进程的后代(子进程或线程组中的)。这应该是递归的(考虑到孩子的孩子)。
Anton Leontiev 的回答给出了这样做的提示:所有文件夹名称/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
Run Code Online (Sandbox Code Playgroud)
如果进程 PID 1234 是您想要递归处理的进程,现在您可以执行以下操作:
renice -n 15 -p $(/path/to/findchildren.sh 1234)
Run Code Online (Sandbox Code Playgroud)
请注意,现在,由于自动任务分组,特别是在使用systemd时,nice 值可能与“系统范围”无关。有关更多详细信息,请参阅此答案。
注意:这个答案准确地解释了 Linux 线程。
简而言之:内核只处理“可运行实体”,即可以运行和调度的东西。内核方面,这些实体称为进程。线程只是一种与另一个进程共享(至少)内存空间和信号处理程序的进程。每个这样的进程都有一个系统范围的唯一标识符:PID(进程 ID)。
因此,您可以 renice单独使用每个“线程”,因为它们确实有自己的PID 1。
1有关 PID (ProcessID) 和 TID 差异 (ThreadID) 的更多信息,请参阅此答案。
根据man renice(强调我的):
renice改变一个或多个正在运行的进程的调度优先级。第一个参数是要使用的优先级值。其他参数被解释为进程 ID(默认情况下)、进程组 ID、用户 ID 或用户名。(...)
事实上,man pgrep作为一个例子,证明了:
示例 4:使所有 chrome 进程运行得更好:
Run Code Online (Sandbox Code Playgroud)$ renice +4 $(pgrep chrome)
根据这些,您可以结合renice使用pgrep的-w | --lightweightswitch 来一次重新启动所有线程,如下所示:
renice <priority> $(pgrep -w <process_name>)
Run Code Online (Sandbox Code Playgroud)
并重新启动所有子进程:
renice <priority> $(pgrep -P $(pgrep <process_name>))
Run Code Online (Sandbox Code Playgroud)
请注意,您还可以使用-fwith 开关pgrep不仅查询进程名称,还可以查询整个命令行(不必完全匹配)。
小智 8
我们不应该混淆进程 PID 和线程 id 有时写入 TID 或在 ps 命令 LPW 中。该s命令具有选项来显示线程和下top或htop你由线程和进程之间切换H信。正如@Totor 之前所说,使用 NPTL(内核 > 2.6 的当前实现),所有线程都具有相同的 pid,但它们具有不同的 tid。您可以通过以下方式显示进程的所有线程:
$ ps -Ljf <pid>
Run Code Online (Sandbox Code Playgroud)
这些 tid 是 下目录的名称/proc/<pid>/task,即使renice(1)说它的默认参数是一个 pid 当应用于 pid 时,它也只会 renice 主线程(这是 linux 实现中的一个错误,如setpriority(2) ) ),它也可以应用于一个 tid 并且它重新定义线程。这就是为什么@Anton 的答案是有效的。
但大多数情况下,有一种更简单的方法可以达到预期的结果,所有这些线程共享相同的 pgid,即组长的 pid;你可以通过 pgid renice 发出:
$ renice -g <pgid>
Run Code Online (Sandbox Code Playgroud)
如果您不想重新启动依赖于同一组长的其他过程,则必须使用@Anton 的配方:
$ renice <priority> $(ls -1 /proc/<pid>/task)
Run Code Online (Sandbox Code Playgroud)
或者:
$renice <priority> $(ps --no-header -Lo tid <pid>)
Run Code Online (Sandbox Code Playgroud)
您可能还想知道与您想要 renice 的进程相比,同一组的其他进程是什么,即共享具有相同 pgid 的进程。您可以使用ps(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'
Run Code Online (Sandbox Code Playgroud)
或者如果你更喜欢 awk 而不是 sed:
$ ps --no-header axo pid,pgid|awk '{if ($2=="1908") print $1;}'
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
12675 次 |
| 最近记录: |