协程

简单的对比和示例

由于协程不如子例程那样被普遍所知，最好对它们作个比较。
子例程的起始处是惟一的入口点，一旦退出即完成了子例程的执行，子例程的一个实例只会返回一次。
协程可以通过yield来调用其它协程。通过yield方式转移执行权的协程之间不是调用者与被调用者的关系，而是彼此对称、平等的。
协程的起始处是第一个入口点，在协程里，返回点之后是接下来的入口点。子例程的生命期遵循后进先出（最后一个被调用的子例程最先返回）；相反，协程的生命期完全由他们的使用的需要决定。
这里是一个简单的例子证明协程的实用性。假设你有一个生产者－消费者的关系，这里一个协程生产产品并将它们加入队列，另一个协程从队列中取出产品并使用它。为了提高效率，你想一次增加或删除多个产品。代码可能是这样的：
var q := new queue
生产者协程
   loop
       while q is not full
           create some new items
           add the items to q
       yield to consume
消费者协程
   loop
       while q is not empty
           remove some items from q
           use the items
       yield to produce
每个协程在用yield命令向另一个协程交出控制时都尽可能做了更多的工作。放弃控制使得另一个例程从这个例程停止的地方开始，但因为现在队列被修改了所以他可以做更多事情。尽管这个例子常用来介绍多线程，实际没有必要用多线程实现这种动态：yield语句可以通过由一个协程向另一个协程直接分支的方式实现。

详细比较

因为相对于子例程，协程可以有多个入口和出口点，可以用协程来实现任何的子例程。事实上，正如Knuth所说：“子例程是协程的特例。”
每当子例程被调用时，执行从被调用子例程的起始处开始；然而，接下来的每次协程被调用时，从协程返回（或yield）的位置接着执行。
因为子例程只返回一次，要返回多个值就要通过集合的形式。这在有些语言，如Forth里很方便；而其他语言，如C，只允许单一的返回值，所以就需要引用一个集合。相反地，因为协程可以返回多次，返回多个值只需要在后继的协程调用中返回附加的值即可。在后继调用中返回附加值的协程常被称为产生器。
子例程容易实现于堆栈之上，因为子例程将调用的其他子例程作为下级。相反地，协程对等地调用其他协程，最好的实现是用continuations（由有垃圾回收的堆实现）以跟踪控制流程。

协程的替代者和实现

到2003年，很多最流行的编程语言，包括C和他的后继，都未在语言内或其标准库中直接支持协程。（这在很大程度上是受基于堆栈的子例程实现的限制）。
有些情况下，使用协程的实现策略显得很自然，但是此环境下却不能使用协程。典型的解决方法是创建一个子例程，它用布尔标志的集合以及其他状态变量在调用之间维护内部状态。代码中基于这些状态变量的值的条件语句产生出不同的执行路径及后继的函数调用。另一种典型的解决方案是用一个庞大而复杂的switch语句实现一个显式状态机。这种实现理解和维护起来都很困难。
在当今的主流编程环境里，线程是协程的合适的替代者，线程提供了用来管理“同时”执行的代码段实时交互的功能。因为要解决大量困难的问题，线程包括了许多强大和复杂的功能并导致了困难的学习曲线。当需要的只是一个协程时，使用线程就过于技巧了。然而——不像其他的替代者——在支持C的环境中，线程也是广泛有效的，对很多程序员也比较熟悉，并被很好地实现，文档化和支持。在POSIX里有一个标准的良定义的线程实现pthread.

Tcl 实现

从 Tcl 8.6 开始，Tcl 核心内置协程支持，成为了继事件循环、线程后的另一种内置的强大功能。