Generator和协程 - Go语言中文社区

Generator和协程


Generator与协程
什么是协程
协程是一种程序运行的方式,可以理解成“协作的线程”或“协作的函数”。协程既可以用单线程实现,也可以用多线程实现。前者是一种特殊的子例程,后者是一种特殊的线程。
协程与子例程的差异
传统的“子例程”(subroutine)采用堆栈式“后进先出”的执行方式,只有当调用的子函数完全执行完毕,才会结束执行父函数。协程与其不同,多个线程(单线程情况下,即为多个函数)可以并行执行,但是只有一个线程(或函数)处于正在运行的状态,其他线程(或函数)都处于暂停态,线程(或函数)之间可以交换执行权。也就是说,一个线程(或函数)执行到一半,可以暂停使用,将执行权交给另一个线程(或函数),等到稍后收回执行权的时候,再回复执行。这种可以并行执行、交换执行权的线程(或函数),就称为协程。
协程和普通线程的差异
协程适合用于多任务运行的环境。在这个意义上,他与不同的简称很相似,都有自己的执行上下文、可以分享全局变量。它们的不同之处在于,同一时间可以有多个线程处于运行状态,但运行的协程只能有一个,其他协程都处于暂停状态。此外,普通的线程是抢先式的,那个线程优先得到资源,是由运行环境决定,但协程是合作式的,执行权由协程自己分配。
JavaScript是单线程语言,只能保持一个调用栈。引入协程后,每个任务可以保持自己的调用栈。这样做能够在抛出错误的时候,找到原始的调用栈(Genterator函数在执行产生上下文环境时,遇到yield命令就会暂时退出堆栈,并不会消失里面所有的变量和对象都会冻结在当前状态,等到对它执行next命令时,这个上下文环境有重新加入调用栈)。不至于出现像异步操作的回调函数那样,一旦出现错误,原始的调用栈早就结束了。

协程的运行流程大致如下:
第一步,协程A开始执行。   
第二步,协程A执行到一半,进入暂停,执行权转移到协程B。  
第三步,(一段时间后)协程B交还执行权。  
第四步,协程A恢复执行。 

Generator函数是ES6对协程的不完全实现。Generator被称为“半协程”,意思是只有Generator函数的调用者,才能将程序的执行权还给Genertor函数。若是完全执行的协程,则人后函数都可以让暂停的协程继续执行。
下面是使用Generator函数实现代码:

function* gen() {
 yield 1;
 return 2;
 }

 let g = gen();

console.log(
g.next().value,
g.next().value,
);

上面代码中,第一次执行g.next()时,Generator 函数gen的上下文会加入堆栈,即开始运行gen内部的代码。等遇到yield 1时,gen上下文退出堆栈,内部状态冻结。第二次执行g.next()时,gen上下文重新加入堆栈,变成当前的上下文,重新恢复执行。

版权声明:本文来源简书,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://www.jianshu.com/p/7e20319dc11a
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-01-12 13:09:22
  • 阅读 ( 1084 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

推荐文章

猜你喜欢