首页 文章

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

提问于
浏览
46

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

  • 进程

  • 主题

  • "Green threads"

  • Protothreads

  • 纤维

  • Coroutines
    Go语言中的

  • "Goroutines"

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

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

4 回答

  • 56

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

    • Process:OS管理(可能)真正并发,至少在适当的硬件支持的情况下 . 存在于自己的地址空间内 .

    • Thread:操作系统管理,与父级及其所有其他线程在同一地址空间内 . 可能真正并发,多任务处于先发制人地位 .

    • Green Thread:这些是与线程相同概念的用户空间投影,但不是由OS管理的 . 可能并非真正并发,除非可能有多个工作线程或进程同时为它们提供CPU时间,因此最好将其视为交错或多路复用 .

    • Protothreads:我无法真正取笑这些定义 . 我认为它们是交错的和程序管理的,但不要相信我的话 . 我的感觉是它们本质上是同一类型的特定于应用程序的实现,并对应用程序域进行了适当的修改 .

    • Fibers:操作系统管理 . 确切的线程,除了合作多任务,因此不是真正的并发 .

    • Coroutines:完全是光纤,除非由OS管理 .

    • Goroutines:他们声称与其他任何东西不同,但它们似乎完全是绿色线程,如在单个地址空间中进行流程管理并复用到系统线程上 . 也许对Go有更多了解的人可以切入营销材料 .

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

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

  • 32

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

    • 流程:

    • 操作系统管理

    • 每个都有自己的虚拟地址空间

    • 系统可以中断(抢占)以允许其他进程运行

    • 可以与不同处理器上的其他进程并行运行

    • 进程的内存开销很高(包括虚拟内存表,打开文件句柄等)

    • 在进程之间创建和上下文切换的时间开销相对较高

    • 主题:

    • 操作系统管理

    • 在某个特定过程中,每个都是"contained"

    • 同一进程中的所有线程共享相同的虚拟地址空间

    • 可以被系统中断以允许另一个线程运行

    • 可以与不同处理器上的其他线程并行运行

    • 与线程关联的内存和时间开销小于进程,但仍然不重要

    • (例如,通常上下文切换涉及进入内核并调用系统调度程序 . )

    • 合作主题:

    • 可能是也可能不是由OS管理的

    • 在某个特定过程中,每个都是"contained"

    • 在某些实现中,每个都是某个特定OS线程中的"contained"

    • 系统不能中断以允许协作对等体运行

    • (当然,包含的进程/线程仍然可以被中断)

    • 必须调用特殊的yield原语以允许对等协作线程运行

    • 一般不能与之并行运行合作伙伴

    • (虽然有些人认为这是可能的:http://ocm.dreamhosters.com/ . )

    • 协作线程主题有很多变化,有不同的名称:

    • 纤维

    • 绿色线程

    • Protothreads

    • 用户级线程(用户级线程可以是可中断/抢占的,但这是一个相对不寻常的组合)

    • 协作线程的某些实现使用分割/分段堆栈等技术,甚至单独堆分配每个调用帧,以减少与为堆栈预分配大块内存相关的内存开销

    • 根据实现,调用阻塞系统调用(如从网络读取或休眠)将导致整组协作线程阻塞或隐式导致调用线程产生

    • 协同程序:

    • 有些人或多或少同义地使用"coroutine"和"cooperative thread"

    • 我不喜欢这种用法

    • 一些协程实现实际上是"shallow"协作线程; yield只能由"coroutine entry procedure"调用

    • 浅(或半协程)版本比线程更容易实现,因为每个协同程序不需要完整的堆栈(只有一个框架用于进入程序)

    • coroutine框架通常有yield原语,要求调用者明确说明哪个协程控制应转移到

    • 发电机:

    • 限制(浅)协同程序

    • yield只能将控制权返回给调用生成器的代码

    • Goroutines:

    • 合作和OS线程的奇怪混合

    • 无法中断(如合作线程)

    • 可以在语言运行时管理的OS线程池上并行运行

    • 事件处理程序:

    • 事件调度程序为响应某些操作而调用的过程/方法

    • 非常适合用户界面编程

    • 几乎不需要语言/系统支持;可以在库中实现

    • 一次最多可以运行一个事件处理程序;在开始下一个调度程序之前,调度程序必须等待处理程序完成(返回)

    • 使同步变得相对简单;不同的处理程序执行永远不会重叠

    • 使用事件处理程序实现复杂任务往往导致"inverted control flow" / "stack ripping"

    • 任务:

    • 由经理向 Worker 池发放的工作单位

    • Worker 可以是线程,进程或机器

    • 当然,任务库使用的工作类型对实现任务的方式有重大影响

    • 在这个不一致且容易混淆的术语列表中,"task"占据了王冠 . 特别是在嵌入式系统社区中,"task"有时用于表示"process","thread"或"event handler"(通常称为"interrupt service routine") . 它有时也通常用于非正式地指代任何类型的计算单位 .

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

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

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

  • 0

    Protothreads只是一个切换案例实现,就像状态机一样,但使软件的实现变得更加简单 . 它基于在case标签之前保存a和int值并返回然后返回到case之后的点的想法,通过读回该变量并使用switch来确定继续的位置 . 因此,protothread是状态机的顺序实现 .

  • 0

    在实现顺序状态机时,Protothread很棒 . Protothreads根本不是真正的线程,而是一种语法抽象,使得编写必须按顺序切换状态(从一个到另一个等等)的开关/案例状态机更加容易 .

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

相关问题