zoukankan      html  css  js  c++  java
  • 协程

    一直对协程(coroutine)的概念不很很懂,看了Wiki中关于Coroutine的条目心里有点而谱了,至少知道协程是什么了。

    通常我们的子例程,比如我们编程语言中的常用的函数,只有一个入口点(Entry Point),那就是你调用这个函数时执行第一行代码,出口点有可能有多个,比如正常执行完最后一行代码,再比如使用return语言在任意一点退出函数。而数据的交换通过参数和返回值来实现。并且这个线程的调用栈,会有Caller的Stack Frame和Callee的Stack Frame。返回的时候Callee的Stack Frame被销毁。Callee能给Caller的也就是返回值。

    什么是协程

    协程比这个复杂一点,他可以有多个入口点。另一点是多次进入这个函数的时候,可以保持这个Callee的进程Stack Frame,所以执行中的环境并不会销毁和重建,而是使用上次执行时候的Stack Frame。有点需要说明的就是我们这里只考虑单线程的情况,这就变得好玩的。在单个线程中,你可以采用协作式的调用和环境保持,而不像多线程中的抢占。Wiki中给的例子是这样的:

    var q := new queue
    
    coroutine produce 
        loop 
            while q is not full 
                create some new items 
                add the items to q 
            yield to consume
    
    coroutine consume 
        loop 
            while q is not empty 
                remove some items from q 
                use the items 
            yield to produce

    你可以指定写作的例程,然后通过Queue来做数据的交换。当前进程让出(yield)控制权给指定例程的时候,指定例程得到执行,而且还保存着上次执行时候的环境,比如内部定义的变量。

    这也是像Golang中Goroutine的做法,只不过Goroutine是可以跨多个虚拟进程的。

    如果一个协程没有使用yield的让出进程,而是执行完最后一条代码退出,这就跟我们普通的例程没有区别的。换种说法例程是协程的一个“特例”。

    生成器

    Python语言中生成器(generator),生成器也可以让出控制权,而且保持上次执行时候的环境。这也是Python中generator最常用的地方,做迭代或者计数这样的工作。

    比如Python中定义和使用一个计数器。

    def gen():
        print "start gen execution"
        for x in xrange(1,10):
            yield x
    
    
    #调用gen函数创建生成器实例,但是其中的代码并没有执行
    #gnext保存了当前生成器的状态,比如还未执行
    gnext = gen()
    
    print 'generator is not executed'
    #next做了两件事
    #1. 如果生成器还没有执行,开始执行。如果已经执行,resume到上次执行的位置继续下次执行
    #2. 将当前yield expression的值返回给caller。
    print gnext.next()  
    print 'first execution and returned the value'
    
    print gnext.next()
    print gnext.next()
    print gnext.next()

    生成器也可以让出控制权,但是跟协程的区别是:生成器是一个能力削弱了的协程,他只能将控制权交给Caller,而不能将控制权交给指定例程。

    那如果要实现producer->comsumer这样的模式的话,需要一个控制例程也就是caller来协调producer和comsumer这两个生成器实例。

    实现协程

    协程最大的优势就是能保持当前的环境,所以在实现的时候如果语言本身不支持协程,可以使用闭包(Closure),用Closure去保持执行的状态,然后使用flag去控制执行流程。

    实现了协程的语言在实现上也有很大的不同,但是基本原则就是解决两个问题:

    1,保持当前协程的Stack在推出后不被释放

    2,跳到上次yield位置继续执行剩下的代码

  • 相关阅读:
    Springboot在IDEA中执行,开启热部署
    java 二分法学习
    python爬虫初级--获取指定页面上的菜单名称以及链接,然后导出
    使用POI读取xlsx文件,包含对excel中自定义时间格式的处理
    Linux CentOS6.8 项目部署脚本实现
    Springboot启动源码详解
    FreeMarker基础语法,宏,引用 等
    在eclipse中启动java程序的时候,每次都会在一个未设置断点的源码里面,卡断点
    Vue学习--
    阿里的maven镜像仓库,eclipse中使用maven下载jar包的时候提升速度
  • 原文地址:https://www.cnblogs.com/Jerry-Chou/p/4197368.html
Copyright © 2011-2022 走看看