【问题标题】:Does multithreading actually work in uniprocessor environment多线程实际上是否在单处理器环境中工作
【发布时间】:2018-12-14 15:25:59
【问题描述】:

假设我们在一个单处理器中有一个具有多个线程的进程。 现在我知道,如果我们有多个进程,那么在单处理器中一次只能处理其中一个,因此这些进程不是并发的。
如果我的理解是正确的,类似地,每个线程将一次处理,而不是在单处理器中并发。这个说法是真的吗?如果是这样,那么多线程是否意味着在一个进程中有多个线程,并不意味着一次运行多个线程?这是否意味着在单处理器环境中创建用户线程没有任何好处?

【问题讨论】:

  • “并发”与“并行”的含义不同。如果两个函数调用在其中任何一个完成之前都已启动,则两个函数调用是并发。即使单个处理器在任何给定时刻只能处理其中一个,它们仍然是并发的。

标签: multithreading operating-system


【解决方案1】:

TL;DR:线程比进程更频繁地切换,实时我们有并发的影响,因为它发生得非常快。

当你写的时候:

每个线程将一次处理,而不是在单处理器中并发

注意“并发”这个词,在 uni 处理器中没有真正的并发,只有在进程之间进行多次上下文切换才会产生这种效果。

让我们在这里澄清一下,CPU 的单核可以在给定时间处理一个线程,每个进程都有一个主线程和(如果需要)更多线程一起运行。如果进程 A 现在正在运行并且它有 3 个线程:A1(主线程)、A2、A3,只要 CPU 内核正在处理进程 A,这三个线程都会运行。当发生上下文切换时,进程 A 不再运行,现在进程 B 将使用他的线程运行。

关于本声明:

在单处理器环境中创建用户线程没有任何好处

这不是真的。创建线程有一个好处,它们更容易创建(如书中的“生成”)和剪切进程堆内存。与线程相比,创建子进程(如书中的“子进程”)是一种开销,因为进程需要拥有自己的内存。例如,每个 google chrome 选项卡都是一个进程而不是线程,但是这个选项卡有多个线程并发运行,几乎没有责任。

【讨论】:

【解决方案2】:

如果您仍然以某种方式运行一台只有一个单核 CPU 的计算机,那么您会发现一次只能物理执行一个线程是正确的。但这并不否定将应用程序分解为多个线程和/或进程的价值。

基本好处是并发。当一个线程正在等待(例如,等待输入/输出操作完成),在此期间,CPU 还要做其他事情:它可以运行一个不同的线程, 't 等待。通过精心设计的应用程序,您可以更好地利用硬件的每个部分,提高并行性,从而提高吞吐量。

我最喜欢的例子是快餐店。大约有十几个工人,每个人都在做不同的事情,合作将您的订单交给您。即使他们中的一个(比如说,“油炸小伙”)站在周围,其他人也总是有事可做。有几个订单同时在处理中。这种重叠,这种“并发”是您所追求的——无论您有多少 CPU。

多线程也常用于需要执行某种“繁重工作”的 GUI 应用程序。一个线程处理 GUI 交互(并且没有其他实际职责),而其他线程,优先级(或“niceness”)稍逊一筹。当一个 GUI 事件到来时,GUI 线程抢占其他线程并立即对其做出响应,然后当然会再次进入睡眠状态。但通过这种方式,GUI 始终保持响应速度非常快——即使其他线程正在做“繁重”的事情,GUI 消息仍然得到非常迅速的处理。 (我通过改造旧应用程序以使用这种方法,获得了大约 25% 的性能提升,因为该应用程序不再“轮询”GUI 事件。)

【讨论】:

【解决方案3】:

我问任何线程的第一个问题是,“它等待为了什么?”对我来说,线程是由它等待什么事件以及它在该事件发生时做什么来定义的。

在多处理器计算机投入市场之前,线程已被广泛使用至少十年。当您要编写一个必须响应来自多个不同来源的非同步事件的程序时,它们很有用。有几种不同的方法可以对这样的程序进行建模。一种方法是让不同的线程等待每个不同的事件源。下一个最受欢迎的是event driven architecture,其中有一个主循环等待所有事件并为每种不同类型的事件调用不同的事件处理函数。

程序的多线程风格通常更容易阅读*,因为程序内部通常有不同的活动,每个活动的状态可以隐含在 context 中(即, 寄存器和调用栈),而在事件驱动模型中,每个活动的状态必须在某个对象中显式编码。

保持状态的隐式上下文方式更接近于procedural style,即我们作为初学者学习的编码单个活动的方式。


*更容易阅读并不意味着代码很容易编写而不会犯错误和不明显的错误!!

【讨论】:

    【解决方案4】:

    开发线程的主要动力是遵守 Ada。在此之前,不同的操作系统有自己的方式同时处理多个事情。在太监中,做不止一件事的方法是分拆一个新的流程。在 VMS 中,软件中断(又名异步系统陷阱或 Windoze 中的异步过程调用)。在那个年代(1970 年代),多处理器系统很少见。

    Ada 的目标之一是拥有一种独立于系统的做事方式。它采用了实际上是一个线程的“任务”。为了支持 Ada,编译器开发人员必须包含任务(线程)库。

    随着多处理器的兴起,操作系统开始使线程(而不是进程)成为系统中的基本可调度单元。

    线程为程序提供了一种同时处理多个事物的方法,即使只有一个处理器。遗憾的是,编程语言中对线程的支持一直非常缺乏。 Ada 是我能想到的唯一一种真正支持线程(任务)的主要语言。例如,Java 中的线程支持就是一个完整的病态笑话。结果是线程在实践中并没有达到应有的效果。

    【讨论】:

      猜你喜欢
      • 2018-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-15
      • 1970-01-01
      相关资源
      最近更新 更多