什么是协程?
协程是一般的控制结构,其中流量控制在两个不同的例程之间协同传递而不返回。
如果您使用过Python或C#,您可能会知道有一个名为yield的关键字,它允许在调用者和被调用函数之间来回循环,直到调用者未使用函数完成或函数由于某种逻辑而终止为止。
样本Python3收益代码
# A Python program to generate numbers in a
# range using yield
def rangeN(a, b):
i = a
while (i < b):
yield i
i += 1 # Next execution resumes
# from this point
for i in rangeN(1, 5):
print(i)
输出 :
1
2
3
4
5
此代码演示了产量如何工作,并简要介绍了如何在调用方和被调用方之间更改控件。
为什么需要协程?
要读取文件并在读取一些有意义的数据时对其进行解析,可以在每一行中逐步读取文件,这很好。您还可以将全部内容加载到内存中,这在大型文本情况下(例如Microsoft Word之类的文本编辑器或在现代系统中仅使用Pipes的情况下,不建议这样做)。
在《计算机编程艺术》中,唐纳德·克努斯(Donald Knuth)为此类问题提供了解决方案。他的答案是完全放弃堆栈概念。停止将一个过程视为呼叫者,将另一个过程视为被呼叫者,并开始将它们视为协作平等。
因此,我们现在可以尝试看看如何在C语言中实现相同的目标。
function read():
/* reads the content in the desired number
of steps and returns back control to parser
but saves its own state of function. */
function parse():
a = read()
while (a)
{
// do something
a = read()
}
好吧,实际上,该结构看起来与C的调用方-被调用方结构非常相似。但是我们在这里需要的是读者必须记住其状态。它必须记住上一次完成任务的时间,并且还应该可以重新设置。
如何在C中实现协程?
挑战在于用C语言编写协程,C本身就是一种基于堆栈的语言,即在C语言中对函数调用的每次响应中,都有一个初始化的堆栈来跟踪其所有变量和常量,并在函数调用时被销毁结束。
int read(void)
{
int i;
for (i = 0; i < 10; i++)
return i; /* Well on the first run itself
the function will be destroyed */
}
我们需要做两件事:
- 将控制恢复到其最后状态
- 通过通话使数据持久化
以上两个问题均应通过使用静态变量来解决。但是如何记住状态并返回到与之前相同的执行状态,即返回或循环后的代码行。我们可以使用GOTO语句。一般不建议这样做。在这里,我们可以尝试一种叫做Duff的设备。
因此,我们终于可以继续使用解决方案代码了。
// C program to demonstrate how coroutines
// can be implemented in C.
#include
int range(int a, int b)
{
static long long int i;
static int state = 0;
switch (state)
{
case 0: /* start of function */
state = 1;
for (i = a; i < b; i++)
{
return i;
/* Returns control */
case 1:; /* resume control straight
after the return */
}
}
state = 0;
return 0;
}
// Driver code
int main()
{
int i; //For really large numbers
for (; i=range(1, 5);)
printf("control at main :%d\n", i);
return 0;
}
输出 :
control at range
control at main :1
control at range
control at main :2
control at range
control at main :3
control at range
control at main :4
该解决方案利用了我们对Duff设备的理解,并使其发挥作用。现在,我们基本上可以在for循环中包含多个return语句,并且每次经过编程就可以返回不同的执行状态。此实现仅模仿Python的range函数,该函数也是基于协程的,因为它从Python3开始返回生成器对象。
来源 :
Simon Tatham在C中的协程