• 协程


    一直对协程(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位置继续执行剩下的代码

  • 相关阅读:
    IOS10.8.2安装
    如何读本地资源图片
    SqlServer2000日志文件过大问题处理
    xcode 4.5.1 免证书开发 破解
    C#生成注册码
    去掉Html标签方法
    数组处理
    返回代码
    Javascript图像处理——图像金字塔
    Javascript图像处理——图像形态学
  • 原文地址:https://www.cnblogs.com/Jerry-Chou/p/4197368.html
Copyright © 2020-2023  润新知