协程、延续和生成器之间有什么区别?
原文由 Mehdi Asgari 发布,翻译遵循 CC BY-SA 4.0 许可协议
协程是轮流执行其工作然后暂停以将控制权交给组中其他协程的几个过程之一。
Continuation 是您传递给某个过程的“指向函数的指针”,当该过程完成时将被执行(“继续”)。
生成器(在 .NET 中)是一种语言构造,它可以吐出一个值,“暂停”方法的执行,然后在询问下一个值时从同一点继续。
原文由 Andriy Volkov 发布,翻译遵循 CC BY-SA 3.0 许可协议
2 回答5.2k 阅读✓ 已解决
2 回答1.1k 阅读✓ 已解决
4 回答1.4k 阅读✓ 已解决
3 回答1.3k 阅读✓ 已解决
3 回答1.2k 阅读✓ 已解决
2 回答861 阅读✓ 已解决
1 回答1.7k 阅读✓ 已解决
我将从生成器开始,因为它们是最简单的情况。正如@zvolkov 提到的,它们是可以重复调用而不返回的函数/对象,但是在调用时将返回(产生)一个值,然后暂停它们的执行。当他们再次被调用时,他们将从上次暂停执行的地方开始并再次做他们的事情。
生成器本质上是一个简化的(非对称的)协程。协程和生成器之间的区别在于协程可以在初始调用后接受参数,而生成器不能。
想出一个使用协程的简单示例有点困难,但这是我最好的尝试。以这段(编造的)Python 代码为例。
使用协程的一个例子是词法分析器和解析器。如果语言中没有协程或以某种方式模拟,词法分析和解析代码需要混合在一起,即使它们实际上是两个独立的问题。但是使用协同程序,您可以分离出词法分析和解析代码。
(我将重述对称协程和非对称协程之间的区别。只要说它们是等价的就够了,你可以从一个协程转换到另一个协程,而非对称协程——最像生成器——是更容易理解。我正在概述如何在 Python 中实现非对称协程。)
延续实际上是非常简单的野兽。它们都是代表程序中另一个点的函数,如果调用它,将导致执行自动切换到该函数代表的点。您每天都在不知不觉中使用它们的非常有限的版本。例如,异常可以被认为是一种由内而外的延续。我会给你一个基于 Python 的延续的伪代码示例。
假设 Python 有一个名为
callcc()
的函数,这个函数有两个参数,第一个是函数,第二个是调用它的参数列表。该函数的唯一限制是它采用的最后一个参数将是一个函数(这将是我们当前的延续)。会发生什么情况是
callcc()
会依次调用foo()
与当前的延续(cc
)callcc()
被调用。当foo()
调用当前延续时,它本质上与告诉callcc()
返回你调用当前延续的值相同,当它这样做时,它回滚堆栈到创建当前延续的位置,即,当您调用callcc()
时。所有这一切的结果是我们假设的 Python 变体将打印
'42'
。