60

我正在阅读并发性。对于具有令人困惑的相似定义的术语,我有点不知所措。即:

  • 流程
  • 线程
  • 《绿线》
  • 原型线程
  • 纤维
  • 协程
  • Go 语言中的“Goroutines”

我的印象是,区别在于 (1) 是真正并行还是多路复用;(2) 是否在 CPU、操作系统或程序中进行管理;和(3..5)其他一些我无法识别的东西。

是否有关于这些并行方法之间差异的简洁明了的指南?

4

4 回答 4

69

好的,我会尽力而为。到处都有警告,但我会尽我最大的努力让我对这些术语和参考的理解与我给出的定义相近。

  • 进程:操作系统管理(可能)真正并发,至少在有合适的硬件支持的情况下。存在于自己的地址空间内。
  • 线程:操作系统管理,在与父线程及其所有其他线程相同的地址空间内。可能是真正并发的,并且多任务是先发制人的。
  • 绿色线程:这些是与线程概念相同的用户空间投影,但不是操作系统管理的。可能不是真正的并发,除非可能有多个工作线程或进程同时为它们提供 CPU 时间,因此最好将其视为交错或多路复用。
  • Protothreads:我真的无法从中挑出一个定义。我认为它们是交错的和程序管理的,但不要相信我的话。我的感觉是,它们本质上是同一种“绿色线程”模型的特定于应用程序的实现,并针对应用程序域进行了适当的修改。
  • 光纤:操作系统管理。完全是线程,除了协同多任务处理,因此不是真正的并发。
  • 协程:完全是纤程,除了不是操作系统管理的。
  • Goroutines:它们声称与其他任何东西都不一样,但它们似乎完全是绿色线程,例如,在单个地址空间中进行进程管理并多路复用到系统线程上。也许对 Go 有更多了解的人可以切入营销材料。

还值得注意的是,在过程演算意义上,术语“过程”的并发理论还有其他理解。这个定义与上面的定义是正交的,但我只是认为值得一提,这样如果你在某个地方看到在这个意义上使用的过程,就不会产生混淆。

另外,请注意parallelconcurrent之间的区别。您可能在问题中使用了前者,而我认为您的意思是后者。

于 2010-07-24T16:58:42.367 回答
41

我大多同意 Gian 的回答,但我对一些并发原语有不同的解释。请注意,这些术语经常被不同的作者不一致地使用。这些是我最喜欢的定义(希望离现代共识不远)。

  • 过程:
    • 操作系统管理
    • 每个都有自己的虚拟地址空间
    • 可以被系统中断(抢占)以允许另一个进程运行
    • 可以与不同处理器上的其他进程并行运行
    • 进程的内存开销很高(包括虚拟内存表、打开的文件句柄等)
    • 进程间创建和上下文切换的时间开销比较高
  • 主题:
    • 操作系统管理
    • 每个都“包含”在某个特定的过程中
    • 同一进程中的所有线程共享相同的虚拟地址空间
    • 可以被系统中断以允许另一个线程运行
    • 可以与不同处理器上的其他线程并行运行
    • 与线程相关的内存和时间开销比进程小,但仍然很重要
      • (例如,通常上下文切换涉及进入内核并调用系统调度程序。)
  • 合作主题:
    • 可能是也可能不是操作系统管理的
    • 每个都“包含”在某个特定的过程中
    • 在一些实现中,每个都“包含”在某个特定的 OS 线程中
    • 不能被系统中断以允许合作对等方运行
      • (当然,包含的进程/线程仍然可以被中断)
    • 必须调用特殊的 yield 原语以允许对等协作线程运行
    • 一般不能与合作伙伴并行运行
    • 合作线程主题有很多变体,名称不同:
      • 纤维
      • 绿线
      • 原型线程
      • 用户级线程(用户级线程可以是可中断的/抢占式的,但这是一个相对不寻常的组合)
    • 协作线程的一些实现使用诸如拆分/分段堆栈之类的技术,甚至单独堆分配每个调用帧以减少与为堆栈预分配大量内存相关的内存开销
    • 根据实现,调用阻塞系统调用(如从网络读取或休眠)将导致整个协作线程组阻塞或隐式导致调用线程屈服
  • 协程:
    • 有些人或多或少将“协程”和“协作线程”同义使用
      • 我不喜欢这种用法
    • 一些协程实现实际上是“浅”的协作线程;yield 只能由“协程入口程序”调用
    • 浅(或半协程)版本比线程更容易实现,因为每个协程不需要完整的堆栈(入口过程只需一帧)
    • 协程框架通常具有 yield 原语,要求调用者明确说明应该将哪个协程控制转移到
  • 发电机:
    • 受限(浅)协程
    • yield 只能将控制权返回给调用生成器的任何代码
  • 协程:
    • 协作线程和操作系统线程的奇怪混合
    • 不能被中断(如协作线程)
    • 可以在语言运行时管理的 OS 线程池上并行运行
  • 事件处理程序:
    • 事件调度程序为响应发生的某些操作而调用的过程/方法
    • 非常流行的用户界面编程
    • 几乎不需要语言/系统支持;可以在库中实现
    • 一次最多可以运行一个事件处理程序;调度程序必须等待处理程序完成(返回),然后再开始下一个
      • 使同步相对简单;不同的处理程序执行永远不会在时间上重叠
    • 使用事件处理程序实现复杂任务往往会导致“反向控制流”/“堆栈撕裂”
  • 任务:
    • 经理分配给工人池的工作单元
    • 工作者可以是线程、进程或机器
      • 当然,任务库使用的工作人员类型对实现任务的方式有重大影响
    • 在这个使用不一致和令人困惑的术语列表中,“任务”占据了首位。特别是在嵌入式系统社区中,“任务”有时用于表示“进程”、“线程”或“事件处理程序”(通常称为“中断服务程序”)。它有时也通用/非正式地用于指代任何类型的计算单元。

我无法阻止自己播出的一个小烦恼:我不喜欢将“真正的并发”一词用于“处理器并行性”。这很常见,但我认为这会导致很多混乱。

对于大多数应用程序,我认为基于任务的框架最适合并行化。大多数流行的(英特尔的 TBB、苹果的 GCD、微软的 TPL 和 PPL)都使用线程作为工作线程。我希望有一些使用流程的好的替代方案,但我不知道有什么。

如果您对并发性(而不是处理器并行性)感兴趣,事件处理程序是最安全的方法。合作线程是一个有趣的选择,但有点狂野的西部。如果您关心软件的可靠性和健壮性,请不要将线程用于并发。

于 2013-05-04T14:55:32.310 回答
0

Protothreads 只是一个 switch case 实现,它就像一个状态机,但使软件的实现变得更加简单。它基于在 case 标签之前保存 a 和 int 值并返回,然后通过读回该变量并使用 switch 来确定从哪里继续来回到 case 之后的点的想法。所以protothread是状态机的顺序实现。

于 2015-02-19T17:58:24.017 回答
0

在实现顺序状态机时,Protothreads 非常棒。Protothreads 根本不是真正的线程,而是一种语法抽象,它使编写必须顺序切换状态(从一个到下一个等)的 switch/case 状态机变得更加容易。

我使用protothreads来实现异步io:http ://martinschroder.se/asynchronous-io-using-protothreads/

于 2015-02-21T08:03:49.483 回答