工艺,线程,绿线,原始线程,纤维,协同程序:有什么区别?

jam*_*her 46 parallel-processing concurrency multithreading process fiber

我正在阅读并发性.对于那些含有令人困惑的类似定义的术语,我有点过头了.即:

  • 流程
  • 主题
  • "绿线"
  • Protothreads
  • 纤维
  • 协同程序
  • Go语言中的"Goroutines"

我的印象是,区别在于(1)是真正的并行还是多路复用; (2)是在CPU,OS还是在程序中管理; 和(3..5)我无法辨认的其他一些事情.

这些并行方法之间的差异是否有简明扼要的指导?

Gia*_*ian 56

好的,我会尽我所能.到处都有警告,但我会尽我所能来理解这些术语,并引用与我给出的定义相近的东西.

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

值得注意的是,在过程微积分意义上,"过程"一词的并发理论还有其他理解.这个定义与上面的定义是正交的,但我只是认为值得一提,所以如果你看到某个地方使用过程,就不会产生混淆.

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


Ben*_*ker 33

我主要赞同Gian的答案,但我对一些并发原语有不同的解释.请注意,这些术语经常被不同作者使用不一致.这些是我最喜欢的定义(希望与现代共识相差不远).

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

一个小小的烦恼,我无法阻止自己播出:我不喜欢使用"真正的并发"这个短语用于"处理器并行".这很常见,但我认为这会导致很多混乱.

对于大多数应用程序,我认为基于任务的框架最适合并行化.大多数流行的(英特尔的TBB,Apple的GCD,微软的TPL和PPL)都使用线程作为工作者.我希望有一些很好的替代品使用过程,但我不知道任何.

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

  • “真正的并发”是并发理论中一种特定并发语义的技术术语。“处理器并行性”可用于实现真正的并发语义。 (2认同)