我从过去2天开始阅读编程艺术,第1卷。
有一个关于子程序和共同例程的主题。 我感到很困惑,当书中提到关于协程在main()之后被初始化的协同例程时,我不能理解,与子例程不同,被调用的协同例程成为调用协同例程的子例程。
我试着在这里研究以前问过的问题,在那里我也在相同的语境中了解了函数和线程的概念 本书给出了一个关于使用MIX计算机模型的协同例程的例子。 我可以使用任何简单的伪代码,让我理解,在目前的高级语言环境中使用一个关于协同例程和其他术语的例子吗?
那么,一个联合问题如何区分子程序,协同例程,函数和线程?
答案 0 :(得分:29)
直到我们从真正了解的人那里得到一个帖子,这是我对这个问题的理解,FWIW。
子程序和函数本质上是一回事,但有一点不同:函数返回某种值(通常通过堆栈或CPU寄存器),而子程序则不然。无论是子程序还是函数,它都是一块可执行代码,只有一个入口点。协同例程也是一个可执行代码块,就像子例程一样,它有一个入口点。但是,它也有一个或多个重返点。稍后会详细介绍。
在进入线程之前,让我们回顾一下:计算机程序(也称为进程)通常将其内存分配组织到代码空间,堆和堆栈中。代码空间存储其可执行代码的一个或多个块。堆栈存储子程序,函数和协同例程(以及其他事项)的参数,自动变量和返回地址。堆是进程可用的广泛内存空间,无论其用途如何。除了这些存储空间之外,还有CPU寄存器,每个寄存器存储一组位。这些位可以是整数值,存储器地址,一堆状态标志等等。大多数程序员不需要了解他们,但他们在那里并且对CPU的操作至关重要。可能值得了解的是程序计数器,堆栈指针和状态寄存器,但我们不会在这里进入它们。
线程是单个逻辑执行流程。在原始计算系统中,只有一个线程可用于进程。在现代计算系统中,进程由一个或多个线程组成。每个线程都有自己的堆栈和一组CPU寄存器(这通常在物理上是不可能的,但在逻辑上是虚拟的 - 我们将在此处跳过一个细节)。但是,虽然进程的每个线程都有自己的堆栈和寄存器,但它们都将共享相同的堆和代码空间。它们(可能)同时运行;可以在多核CPU中真正发生的事情。因此,程序的两个或多个部分可以同时运行。
回到协同例程:如前所述,它有一个或多个重新进入点。重新进入意味着协同例程可以允许其他一些代码块本身具有一些执行时间,然后在某个将来的某个时间将执行时间恢复到其自己的代码块内。这意味着只要执行到外部代码块然后返回到协同例程的代码块,就会保留(并在需要时恢复)协同例程的参数和自动变量。虽然常见于许多汇编语言,但协同例程并不是直接在每种编程语言中实现的。在任何情况下,都可以以概念的方式实现协同例程。在http://en.wikipedia.org/wiki/Coroutine有一篇关于协同例程的好文章。
在我看来,实施协同常规设计模式有两个主要动机:(1)克服单线程流程的局限性; (2)希望实现更好的计算性能。动机(1)很清楚,当过程必须同时解决许多事情时,单个线程是必须的。动机(2)可能不太清楚,因为它与系统硬件,编译器设计和语言设计的许多细节有关。我只能想象,通过减少堆栈操作,避免在子例程中重做初始化,或者减轻维护多线程进程的一些开销,可以减少计算工作量。
HTH
答案 1 :(得分:23)
关注协程与子程序:
协程可以产生,这很有趣。
产量'记住'当共同例程再次被调用时,它会在它停止的地方继续。
例如:
coroutine foo {
yield 1;
yield 2;
yield 3;
}
print foo();
print foo();
print foo();
打印: 1 2 3
注意:协同程序可以使用返回,并且表现得像子程序
coroutine foo {
return 1;
return 2; //Dead code
return 3;
}
print foo();
print foo();
print foo();
打印: 1 1 1
答案 2 :(得分:2)
我想扩展现有答案,增加以下内容:
在调用一段代码时存在4个主要概念:
在子程序中,创建和恢复与“调用”指令同时发生 - 堆栈帧被分配,参数和返回地址被推送,执行跳转到被调用的代码段。此外,分离(恢复调用者)和销毁与“返回”指令同时完成 - 堆栈帧被解除分配,控制被转移到调用者(通过先前提供的返回地址)并且调用者被留下来搜集垃圾用于挑选返回值的堆栈(取决于您的调用约定) 在协同程序中,这些主要概念是独立存在的,彼此分离。你可以在某个时候创建一个协同程序,然后你可以稍后将控制转移到它(因此它可以产生一些结果,可能多次),然后你可以在以后的某个时间点销毁它。
答案 3 :(得分:1)
协同程序只是并发子程序(函数,方法,闭包),它们是非抢占式的。也就是说它们不能被中断,而协同程序有多个点可以允许多个暂停点或范围重新进入。
Coroutines是隐式并发构造,但并发性不是协程的属性:必须同时托管多个协同程序,并给每个协同程序执行否则,它们不会并发!请注意,这并不意味着协同程序是隐式并行的。
答案 4 :(得分:1)
来自python文档,
协程是子程序的一种更通用的形式。子例程在一个点进入,在另一点退出。协程可以在许多不同点进入,退出和恢复。可以使用async def语句实现它们。
答案 5 :(得分:0)
的差异: (1)当子程序具有时,协同例程没有主从关系。 (2)子程序具有单个入口点,而共同程序可具有多个入口点。 (3)在执行被调用子程序期间暂停调用程序。协同例程提供准并发执行。 相似点: (1)协同例程和子例程都能够使用return。 (2)协同例程和子例程的执行不重叠。