进程,线程,绿色线程,原线程,纤维,协程:有什么区别?

我正在阅读并发。 我的脑海中有一些混淆相似的定义。 即:

  • stream程
  • 主题
  • “绿色线索”
  • Protothreads
  • 纤维
  • 协同程序
  • Go语言中的“Goroutines”

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

对于这些并行性方法之间的差异,有没有一个简洁而明确的指导?

好吧,我会尽我所能。 有各种各样的警告,但我会尽我所能,让我理解这些术语和参考近似我给定义的东西。

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

同样值得注意的是,在过程演算的意义上,“过程”一词的并发理论还有其他的理解。 这个定义与上面的定义是正交的,但是我只是觉得值得一提,所以如果你看到某个地方的stream程被使用了,那么就不会出现混淆。

另外,请注意并行和并发之间的区别。 你可能在你的问题中使用前者,我认为你的意思是后者。

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

  • 处理:
    • OSpipe理
    • 每个都有自己的虚拟地址空间
    • 可以被系统中断(抢占)以允许另一个进程运行
    • 可以在不同处理器上与其他进程并行运行
    • 进程的内存开销很大(包括虚拟内存表,打开文件句柄等)
    • 在进程之间创build和上下文切换的时间开销相对较高
  • 主题:
    • OSpipe理
    • 在某个特定的过程中,每个“被包含”
    • 同一进程中的所有线程共享相同的虚拟地址空间
    • 可以被系统中断以允许另一个线程运行
    • 可以与不同处理器上的其他线程并行运行
    • 与线程相关的内存和时间开销比进程小,但仍然不平凡
      • (例如,通常上下文切换涉及进入内核并调用系统调度程序。)
  • 合作线程:
    • 可能或不可以由操作系统pipe理
    • 在某个特定的过程中,每个“被包含”
    • 在一些实现中,每个在某个特定的OS线程内被“包含”
    • 不能被系统中断以允许合作伙伴运行
      • (当然,包含进程/线程仍然可以中断)
    • 必须调用特殊的yield基元以允许对等协作线程运行
    • 一般不能与合作伙伴同步运行
      • (尽pipe有些人认为这是可能的: http : //ocm.dreamhosters.com/ 。)
    • 合作主题主题中有很多不同的变体:
      • 纤维
      • 绿色的线程
      • Protothreads
      • 用户级线程(用户级线程可以是可中断/抢占的,但是这是一个相对不寻常的组合)
    • 协作线程的一些实现使用诸如分割/分段堆栈之类的技术,或者甚至单独堆分配每个调用帧以减less与为堆栈预分配大块内存相关联的内存开销
    • 根据实现的不同,调用阻塞系统调用(如从networking读取或hibernate)将导致整组协作线程阻塞或隐式地导致调用线程产生
  • 协同程序:
    • 有些人或多或less同意使用“协同程序”和“协作线程”
      • 我不喜欢这种用法
    • 一些协程实现实际上是“浅”的协作线程; 收益率只能由“协同进入程序”调用
    • 浅(或半协程)版本比线程更容易实现,因为每个协程不需要一个完整的堆栈(只有一个入口过程的框架)
    • 通常,协同程序框架具有屈服原语,要求调用者明确指出哪个协程控制应该传递给哪个协程
  • 发电机:
    • 受限(浅)协程
    • yield只能将控制权返回给调用生成器的任何代码
  • 够程:
    • 一个奇怪的混合的合作和操作系统线程
    • 不能被打断(像合作的线程)
    • 可以在OS线程的语言运行时pipe理的池上并行运行
  • 事件处理程序:
    • 由事件调度程序响应某些操作而调用的过程/方法
    • 用户界面编程非常stream行
    • 几乎不需要语言/系统支持; 可以在图书馆实施
    • 一次只能运行一个事件处理程序; 调度员必须等待处理程序完成(返回)才能开始下一个
      • 使同步相对简单; 不同的处理程序执行不会在时间上重叠
    • 使用事件处理程序执行复杂的任务往往会导致“反向控制stream”/“堆栈翻录”
  • 任务:
    • 经理向工作人员分配的工作单位
    • 工人可以是线程,进程或机器
      • 当然,任务库使用的这种工作人员对于如何执行任务有着重大的影响
    • 在这个不一致和混淆使用的术语列表中,“任务”取冠。 特别是在embedded式系统社区中,“任务”有时用来表示“进程”,“线程”或“事件处理程序”(通常称为“中断服务程序”)。 它有时也被用于一般/非正式地指代任何种类的计算单位。

我无法阻止自己的发泄:我不喜欢使用“真并发”这个词来表示“处理器并行性”。 这很常见,但我认为这会导致很多混乱。

对于大多数应用程序,我认为基于任务的框架最适合并行化。 大部分受欢迎的(Intel的TBB,苹果的GCD,微软的TPL&PPL)使用线程作为工作者。 我希望有一些很好的替代scheme使用过程,但我不知道任何。

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

Protothreads只是一个开关盒的实现,它像状态机一样工作,但使软件的实现变得更简单。 它基于在一个case标签之前保存一个int值的思想,然后返回,然后通过回读该variables并使用开关来确定继续的位置,从而返回到该case之后的点。 所以protothread是一个状态机的顺序执行。

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

我已经使用protothreads来实现asynchronousio: http ://martinschroder.se/asynchronous-io-using-protothreads/