Linux时间分割进程还是线程?

一位教授曾经在课堂上告诉我们,Windows,Linux,OS X和UNIX在线程上而不是在进程上扩展,因此,即使在单个处理器上,线程也可能会使应用程序受益,因为应用程序将在CPU上获得更多时间。

我试着用我的机器上的以下代码(它只有一个CPU)。

#include <stdio.h> #include <stdlib.h> #include <pthread.h> pthread_t xs[10]; void *nop(void *ptr) { unsigned long n = 1UL << 30UL; while(n--); return NULL; } void test_one() { size_t len = (sizeof xs) / (sizeof *xs); while(len--) if(pthread_create(xs+len, NULL, nop, NULL)) exit(EXIT_FAILURE); len = (sizeof xs) / (sizeof *xs); while(len--) if(pthread_join(xs[len], NULL)) exit(EXIT_FAILURE); } void test_two() { size_t len = (sizeof xs) / (sizeof *xs); while(len--) nop(NULL); } int main(int argc, char *argv[]) { test_one(); // test_two(); printf("done\n"); return 0; } 

两个testing在速度方面是相同的。

 real 0m49.783s user 0m48.023s sys 0m0.224s 

 real 0m49.792s user 0m49.275s sys 0m0.192s 

这个我想,“哇,线程吮吸”。 但是,在四台处理器的大学服务器上重复testing接近四倍的速度。

 real 0m7.800s user 0m30.170s sys 0m0.006s 

 real 0m30.190s user 0m30.165s sys 0m0.004s 

当我解释我的家用机器的结果时,我可以忽略一些东西吗?

Solutions Collecting From Web of "Linux时间分割进程还是线程?"

为了理解内部任务/线程…让我们看看这个玩具内核代码…

结构regs {
   int eax,ebx,ecx,edx,es,ds,gs,fs,cs,ip,flags;
   struct tss * task_sel;
 }

结构线程{
    结构regs * regs;
     int parent_id;
     struct thread * next;
 }
结构任务{
   结构regs * regs;
    int * phys_mem_begin;
    int * phys_mem_end;
    int *文件句柄;
   优先
    int * num_threads;
   诠释量子
   整数持续时间
    int start_time,end_time;
    int parent_id;
   结构线程* task_thread;
      / * ... * /
    struct task * next;
 }

想象一下,内核为结构task (这是一个链表)分配内存,仔细观察quantum领域,即基于priority领域的处理器时间的时间片。 总是会有一个ID 0的任务,它不会睡觉,只是空闲,也许发出nops(没有OPerationS)…调度器围绕广告nauseum旋转,直到无限(即电源被拔下),如果quantum场决定任务运行20ms,设置start_timeend_time + 20ms,当end_time启动时,内核将cpu寄存器的状态保存到regs指针中。 进入链中的下一个任务,将cpu寄存器从指针加载到regs并跳转到指令中,设置量程和持续时间,当持续时间达到零时,继续下一个有效的上下文切换。这是什么使它在一个CPU上同时运行的错觉。

现在看看thread结构,它是task结构中的线程链接列表。 内核为该任务分配线程,为该线程设置CPU状态,并跳转到线程中…现在内核必须管理线程以及任务本身…再次在任务和线程之间的上下文切换…

移动到一个多CPU,内核将被设置为可扩展的,调度程序会做什么,将一个task加载到一个CPU,另一个加载到另一个CPU(双核),并跳转到指令的地方指针指向…现在内核真的在两个CPU上同时运行这两个任务。 扩展到4路,同样的东西,加载到每个CPU上的附加任务,再次扩展,以n路…你得到的漂移。

正如你所看到的那样,线程不会被视为可扩展的概念,因为内核在跟踪cpu运行什么方面非常坦率地工作,而且最重要的是运行哪些线程,从根本上来说解释了为什么我认为线程不完全可扩展…线程消耗了大量的资源…

如果您真的想看看发生了什么,请查看Linux的源代码,特别是在调度程序中。 没有挂,忘记了2.6.x内核版本,看史前版本0.99,调度程序会更容易理解,更容易阅读,当然,它有点旧,但值得一看,这将有助于你理解为什么,也希望我的答案,为什么线程不可扩展……并显示玩具操作系统如何使用基于进程的时间划分。 我努力不去涉及现代CPU的技术方面,可以做更多的事情,正如我所描述的…

希望这可以帮助。

一位教授曾经在课堂上告诉我们,Windows,Linux,OS X和UNIX在线程上而不是在进程上扩展,所以即使是在单个处理器上,线程也可能会对你的应用程序有利,因为你的应用程序在CPU上获得更多的时间。

不必要。 如果你的应用程序是唯一的CPU密集型的东西运行,更多的线程不会神奇地使更多的CPU时间可用 – 所有这些将导致上下文切换浪费更多的CPU时间。

这个我想,“哇,线程吮吸”。 但是,在四台处理器的大学服务器上重复测试接近四倍的速度。

这是因为有四个线程,它可以使用全部四个处理器。

我不确定你在问什么,但这里有一个答案,可能有帮助。

在Linux下,进程和线程本质上是完全一样的。 调度器理解所谓的“任务”,它并不关心它们是否共享地址空间。 共享或不共享的东西真的取决于他们是如何创建的。

是否使用线程或进程是一个关键的设计决策,不应掉以轻心,但调度程序的性能可能不是一个因素(当然,像IPC的要求会大大改变设计)