zoukankan      html  css  js  c++  java
  • 函数和常用模块【day05】:生成器并行计算(五)

    本节内容

    1、概述

    2、生成器执行原理

     

    3、send()和__next__()方法的区别

     

    4、yield实现并行效果

    一、概述

      之前只是介绍生成器,那有些同学就说了,这个生成器除了能节省资源,提高工作效率,但是我们再哪些场景下可以用呢?在哪些地方可以体现出它的价值呢?下面我们来逐一解答这些疑问。

    二、生成器执行原理

    1、执行原理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    def consumer(name):
        print("%s 准备吃包子啦!"%name)
     
        while True:
            baozi = yield
     
            print("包子[%s]来了,被[%s]吃了"%(baozi,name))
     
    = consumer("zhangqigao")
    c.__next__()
     
    #输出
    zhangqigao 准备吃包子啦!

     如果我再加一个__next__()方法会有什么效果?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    def consumer(name):
        print("%s 准备吃包子啦!"%name)
     
        while True:
            baozi = yield
     
            print("包子[%s]来了,被[%s]吃了"%(baozi,name))
     
    = consumer("zhangqigao")
    c.__next__()
    c.__next__()
     
    #输出
    zhangqigao 准备吃包子啦!
    包子[None]来了,被[zhangqigao]吃了

     很明显,第一种情况没有执行"print("包子[%s]来了,被[%s]吃了"%(baozi,name))",这段代码,接下来我们就来调试一下。

    2、调试

    第一步:生成一个生成器

    第二步:执行第一个__next__()方法进入函数,执行到yield时中断,把返回值返回给baozi这个变量:

    第三步:开始执行下面的程序,也就执行到了第二个__next__()方法,直接跳转到yield这边,继续上一次的中断往下执行,这样就执行了yield下面的程序,当再次执行到yield关键字时,则继续中断,并且把返回值赋给baozi关键字,如果下面没有其他程序,则程序结束。

     小结:

    1. 用yield做生成器,你想把什么返回到外面,你就把yield关键字放在那里。
    2. yield其实是保留了函数的中断状态,返回当前的值。
    3. 如果yield没有返回值,就返回一个空值None

    三、send()和__next__()方法的区别

    1、send()方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    def consumer(name):
        print("%s 准备吃包子啦!"%name)
     
        while True:
            baozi = yield
     
            print("包子[%s]来了,被[%s]吃了"%(baozi,name))
     
    = consumer("zhangqigao")
    c.__next__()  #不使用__next__()方法会报错
    b1 = "肉松馅"
    c.send(b1)   #调用yield,同时给yield传一个值
    b2 = "韭菜馅"
    c.send(b2)
     
    #输出
    zhangqigao 准备吃包子啦!
    包子[肉松馅]来了,被[zhangqigao]吃了
    包子[韭菜馅]来了,被[zhangqigao]吃了

     从上面可以看出send()和__next__()方法的区别:

    1. __next__()只是调用这个yield,也可以说成是唤醒yield,但是不不会给yield传值。
    2. send()调用这个yield或者说唤醒yield同时,也活给yield传一个值。
    3. 使用send()函数之前必须使用__next__(),因为先要中断,当第二次调用时,才可传值。

    为什么给消费者传值时,必须先执行__next__()方法?

    因为如果不执行一个__next__()方法,只是把函数变成一个生成器,你只有__next__()一下,才能走到第一个yield,然后就返回了,调用下一个send()传值时,才会发包子。

    四、yield实现并行效果

    yield还有一个更强大的功能,就是:单线程实现并发效果。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    import time
     
    def consumer(name):
        print("%s 准备吃包子啦!"%name)
     
        while True:
            baozi = yield
     
            print("包子[%s]来了,被[%s]吃了"%(baozi,name))
     
     
    def producer(name):
        = consumer("A")
        c2 = consumer("B")
        c.__next__()
        c2.__next__()
        print("老子准备吃包子啦!")
        for in range(10):
            time.sleep(1)
            print("做了一个包子,分两半")
            c.send(i)
            c2.send(i)
     
    producer("zhangqigao")

     这个是生产者消费者模式,这个也就是后面协程的效果,这个我们后续再讲,先了解一下,生成器可以实现并发效果,极大的提高程序的运行效率。

  • 相关阅读:
    .Net中DataGridview数据如何导出到excel表
    SQLSEVER 中的那些键和约束
    数据仓库中数据粒度
    详解三层架构图
    三层概念总结
    SQL Sever 2008配置工具中过程调用失败解决方法
    设计模式之中介者模式
    设计模式之访问者模式
    设计模式之代理模式
    设计模式之迭代器模式
  • 原文地址:https://www.cnblogs.com/luoahong/p/7195752.html
Copyright © 2011-2022 走看看