好的优先级和调度程序策略与 Linux 中的进程(线程?)ID 有何关系?
我正在研究如何在后台运行 CPU 密集型任务时让 Linux 桌面体验保持流畅和交互。下面是我用来模拟 CPU 负载的示例程序(用 Java 编写):
public class Spinner {
public static void main(String[] args)
{
for (int i = 0; i < 100; i++) {
(new Thread(new Runnable() {
public void run() {
while (true);
}
})).start();
}
}
}
当我在命令行上运行该程序时,我注意到桌面应用程序(例如文本编辑器)的交互性显着下降。我有双核机器,所以我对此并不感到惊讶。
为了解决这个问题,我的第一个想法是使用 renice -p 20
我对此感到非常困惑,因为我不希望线程有自己的进程 ID。即使他们这样做了,我也希望 renice 能够作用于整个进程,而不仅仅是进程的主线程。
有人清楚地了解这里发生了什么吗?看来每个线程实际上都是一个单独的进程(至少它有一个有效的PID)。我知道 Linux 历史上是这样工作的,但我相信 NPTL 几年前就解决了这个问题。
我正在 RHEL 5.4(linux 内核 2.6.18)上进行测试。
(顺便说一句。如果我尝试使用 sched_setscheduler(/proc/
中看到的所有“子”进程,在主程序 pid 上执行一次是不够的。)
I am investigating how to have my Linux desktop experience remain smooth and interactive while I run CPU intensive tasks in the background. Here is the sample program (written in Java) which I am using to simulate CPU load:
public class Spinner {
public static void main(String[] args)
{
for (int i = 0; i < 100; i++) {
(new Thread(new Runnable() {
public void run() {
while (true);
}
})).start();
}
}
}
When I run this on the command line, I notice that the interactivity of my desktop applicaitons (e.g. text editor) drops significantly. I have a dual core machine, so I am not suprised by this.
To combat this my first thought was to nice the process with renice -p 20 <pid>
. I found however that this doesn't have much affect. I instead have to renice all of the child processes with something like ls /proc/<pid>/task | xargs renice 20 -p --
which has a much greater effect.
I am very confused by this, as I would not expect threads to have their own process IDs. Even if they did I would expect renice
to act on the entire process, not just the main thread of the process.
Does anyone have a clear understanding of what is happening here? It appears that each thread is actually a seperate process (at least it has a valid PID). I knew that historically Linux worked like this, but I believed NPTL fixed that years ago.
I am testing on RHEL 5.4 (linux kernel 2.6.18).
(As an aside. I notice the same effect if I try to use sched_setscheduler(<pid>, SCHED_BATCH, ..)
to try to solve this interactivity problem. Ie, I need to make this call for all the "child" processes I seee in /proc/<pid>/task
, it is not enough to perform it once on the main program pid.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
线程 ID 与 PID 来自同一命名空间。这意味着每个线程都可以通过其 TID 单独寻址 - 某些系统调用确实适用于整个进程(例如,
kill
),但其他系统调用仅适用于单个线程。调度程序系统调用通常属于后一类,因为这允许您为进程中的不同线程提供不同的调度程序属性,这通常很有用。
Thread IDs come from the same namespace as PIDs. This means that each thread is invididually addressable by its TID - some system calls do apply to the entire process (for example,
kill
) but others apply only to a single thread.The scheduler system calls are generally in the latter class, because this allows you to give different threads within a process different scheduler attributes, which is often useful.
据我了解,在 Linux 上,线程和进程几乎是同一件事;线程恰好是共享相同内存的进程,而不是执行 fork 的写时复制操作,并且 fork(2) 和 pthread_create(3) 大概都只是分层到调用 clone(2) 具有不同的参数。
调度的东西非常令人困惑,因为例如 pthreads(7) 手册页首先告诉你的 Posix 线程共享一个共同的好值,但是你必须认真对待
来查看整个图片(并且我确信有很多甚至不太有用的手册页)。
我编写过从主 UI 线程生成多个计算线程的 GUI 应用程序,并且始终发现让应用程序保持快速响应的关键是调用 nice(2) 在计算线程中(仅);将其增加 4 左右似乎效果很好。
或者至少我记得就是这么做的。我只是多年来第一次查看代码,看看我实际上做了什么:
这很有趣。我可能尝试过nice(2),发现它实际上适用于整个过程(所有线程),这不是我想要的(但也许你想要)。但这已经是很多年前的事情了。从那时起,行为可能已经改变。
当你玩这类东西时,一个重要的工具是:如果你在 top(1),它从进程视图变为显示所有线程和单个线程的nice值。例如,如果我运行
[evolvotron][7] -t 4 -n 5
(nice 5 处的 4 个计算线程)我明白(我只是在一台旧的单核非 HT 机器上,所以不是实际上这里多线程很重要):As I understand it, on Linux threads and processes are pretty much the same thing; threads just happen to be processes which share the same memory rather than doing fork's copy-on-write thing, and fork(2) and pthread_create(3) are presumably both just layered onto a call to clone(2) with different arguments.
The scheduling stuff is very confusing because e.g the pthreads(7) man page starts off by telling you Posix threads share a common nice value but then you have to get down to
to see the whole picture (and I'm sure there are plenty of even less helpful man pages).
I've written GUI apps which spawn multiple compute threads from a main UI thread, and have always found the key to getting the app to remain very responsive is to invoke nice(2) in the compute threads (only); increasing it by 4 or so seems to work well.
Or at least that's what I remembered doing. I just looked at the code for the first time in years and see what I actually did was this:
Which is interesting. I probably tried nice(2) and found it did actually apply to the whole process (all threads), which wasn't what I wanted (but maybe you do). But this is going back years now; behaviour might have changed since.
One essential tool when you're playing with this sort of stuff: if you hit 'H' (NB not 'h') in top(1), it changes from process view to showing all the threads and the individual thread nice values. e.g If I run
[evolvotron][7] -t 4 -n 5
(4 compute threads at nice 5) I see (I'm just on an old single core non-HT machine, so not actually much point in multiple threads here):