![任务管理器显示系统正在运行超过一千个线程](https://linux22.com/image/1369373/%E4%BB%BB%E5%8A%A1%E7%AE%A1%E7%90%86%E5%99%A8%E6%98%BE%E7%A4%BA%E7%B3%BB%E7%BB%9F%E6%AD%A3%E5%9C%A8%E8%BF%90%E8%A1%8C%E8%B6%85%E8%BF%87%E4%B8%80%E5%8D%83%E4%B8%AA%E7%BA%BF%E7%A8%8B.png)
答案1
简单的答案是并非所有线程都同时执行。如需更完整的解释,请继续阅读。
操作系统的任务调度程序通常被认为是用来调度应用程序的,这样你就可以在计算机执行一项任务的同时执行另一项任务。在过去,多任务处理的试金石是一边做其他事情一边格式化软盘。如果你想真正测试操作系统,你会一边格式化软盘一边通过连接到串行端口的调制解调器下载文件。随着硬件变得足够强大,可以真正以有意义的方式做到这一点,视频播放有时也会出现在这样的测试中。如果操作系统的任务调度程序可以顺利运行这些任务,那么它就可以处理任何事情。
但是,任务调度程序实际上并不调度应用程序(进程),它调度线程。每个应用程序至少有一个线程,但可能会使用大量线程将其工作拆分为相关或独立的部分。例如,应用程序通常有一个处理用户界面的线程,并在用户启动可能长时间运行的操作(可能是打印、重新计算电子表格、开发环境执行符号查找等)时创建另一个线程。一些编程环境会引入一些对程序员不可见的线程;例如,Java和。网可能做垃圾收集在一个单独的线程中,这不受程序员的直接控制。有些程序在早期创建多个线程并将它们池化,因为创建新线程是一项相对昂贵的操作(因此您不一定希望每次需要时都必须创建一个线程)。执行预览的任何操作通常都在单独的线程中完成,因此在生成预览时,UI 的其余部分仍保持响应。等等。综合起来,所有这些意味着系统中任何时候的线程数很容易达到进程数的很多倍。
每个线程可能处于几种可能的状态之一,但最重要的区别是跑步,可运行和等待状态;术语可能略有不同,但基本思想是这样的。在任何时候,每个虚拟(由于超线程和类似技术)CPU 核心只能运行一个线程跑步(即执行机器代码指令),但可以有任意数量的线程可运行(这意味着下次调度程序需要决定哪个线程应该被允许运行时,它是获得 CPU 的候选者)。等待(也称为阻塞) 线程就是在等待某事 - 最常见的情况可能是等待用户、磁盘或网络 I/O(特别是用户输入非常慢)。
您在任务管理器中看到的线程数是线程总数在任何这些状态下。例如,我输入本文的 Windows 7 系统目前已启动了大约 70 个进程,但线程数接近 900 个。考虑到所有后台进程都用于处理各种任务,并且每个进程可能细分为多个线程,这个数字并不离谱。
更深入地了解技术实现,抢占式多任务操作系统的任务调度程序的核心通常是某种硬件中断钩子。这意味着内核可以在没有有用的工作要执行时停止 CPU(这几乎肯定是原因之一,如果不是这Linux 检查的原因指令HLT
在启动时IA-32兼容 CPU,并且可能在其他架构上进行类似检查),因为知道在某个合理确定的未来时间,中断将触发,任务调度程序将被调用。由于中断无论 CPU 正在执行什么其他工作都会触发(这是中断背后的想法),调度程序会定期执行,并有机会确定在下一个时间片中应该执行哪个线程。由于上下文切换相对昂贵,因此通常可以(至少通过源代码)调整调度程序在线程之间切换的积极程度;更频繁地切换线程会使系统变得更灵敏,但切换开销意味着完成给定任务集的总时间更长。最快的系统将只在正在运行的线程不再可能运行时(意味着它在等待某事时被阻塞,或者它已经完成了它的工作)在线程之间切换,因为这样可以最大限度地减少开销,而反应最灵敏每次调用调度程序时,系统都会在线程之间切换,因为这可以最大限度地减少特定线程获得 CPU 时间之前的平均等待时间。理想的设置通常介于这两者之间,而这些选择之间的权衡可能是 Linux 提供多个调度程序供选择以及通过内核配置提供一些调整参数的一个重要原因。
另一方面,协作多任务操作系统和环境(Windows 3.x举个例子),依赖于每个应用程序定期将控制权移交给调度程序。通常有一个专门用于执行此操作的 API 函数,而且很多 API 函数都会将其作为内部执行流程的一部分,因为这有助于让用户体验更流畅。只要所有应用程序都表现良好,并在任何长时间运行的操作(长时间运行意味着超过一秒的一小部分)期间以短间隔移交控制权,这种设计方法就会很有效,但如果应用程序不这样做,就会堵塞整个系统。这就是为什么 Windows 3.x 在我上面提到的多任务测试中表现如此糟糕的一个主要原因,而操作系统/2在相同的硬件上执行相同的任务时,可以愉快地漫步:应用程序可以告诉软盘驱动器写入某个扇区,并且在调用返回之前执行此操作所花费的时间实际上是可以测量的(几十到几百毫秒或更长);抢占式多任务系统会让它的调度程序在下一次计划调用时中断,注意到当前“运行”的线程实际上被写入调用阻止,然后简单地切换到另一个可运行的线程。(实际上它有点复杂,但这就是一般的想法。)
在抢占式多任务和协作式环境中,不同的线程也可能具有不同的优先级。例如,及时执行通过通信链路接收数据的线程可能比更新系统时间显示的线程更重要,因此接收线程具有高优先级,而时间显示更新线程具有低优先级。线程优先级在调度程序决定允许执行哪个线程方面发挥着作用(例如,非常简单,高优先级线程应该始终在低优先级线程之前执行,因此即使低优先级线程还有工作要做,如果高优先级线程变为可运行状态,则高优先级线程优先执行),但这种特定的调度决策不会影响底层机制设计。
答案2
想象一下一条有 1037 辆车的四车道高速公路。
您的操作系统需要运行大量进程才能为大量服务工作。即使是最简单的图形程序也需要多线程编程。当您想到打开的大量程序时,您会发现需要共享计算能力资源。
任务管理器显示的是当前系统负载。计算机规格显示的是接受多少个线程(在前端)进行并行执行。无需过多考虑超线程和多核功能之间的差异,前端线程接受越合理,系统通常性能就越好。
答案3
我们应该退一步问自己:一台只有一个 CPU 的计算机怎么会有两个线程呢?
线程是软件实体,而不是硬件。要拥有另一个线程,您只需要为组成该线程的对象(例如描述符结构和堆栈)分配内存。
操作系统在不同的时间在线程之间切换,例如在某些中断(例如计时器中断)内或当线程调用操作系统时。
在系统中存在的所有线程中,通常只有一小部分处于通常称为“可运行”的状态。可运行线程渴望运行:它们要么正在执行,要么位于“运行队列”中,等待调度程序调度。非可运行线程被“阻塞”,等待获取某些资源或接收输入,或“休眠”,就像被输入阻塞一样,其中“输入”是时间的流逝。当操作系统中的调度程序功能查看处理器的运行队列并选择要执行的其他线程时,就会发生“上下文切换”。
不要混淆“超线程”,这是英特尔对某一特定硬件功能的名称。