生成器来这吧

提到生成器我们先引入yield,greenlet,gevent,这三个是有关协程的概念,python三大器(迭代器,生成器,装饰器)之一,协程是python特有的概念,其他语言也许有多线程,多进程,当然python里也有,不过在python有一种特殊的多任务叫做协程,协程也是通过线程是实现的,量级很小的线程,所以也叫微线程。

目录

1.yield简介

2.greenlet简介

三.gevent简介

四,总结


1.yield简介

我们可以简单的先理解一下只要一个方法里拥有yield这个方法,就称这样的方法为生成器我们先写个demo,感受一下

代码演示:

def generate_num():
    count = 0
    while count < 10:
        yield count
        count += 1

obj_generate = generate_num()   # 创建生成器对象
for num in obj_generate:
    print(num)     # 意图是循环打印上面count的值


'''
0
1
2
3
4
5
6
7
8
9
'''

从结果看来,发现生成器创建的对象是个可迭代对象,且有迭代的方法在其中,所以在这里我们可以看出生成器是个特殊的迭代器。我们返回来说说这个yield这个是怎么是现实的

yield大概就是这样实现的,(图丑勿怪O.o),其中的思想就是通过生成器生成对象,对生成器对象进行迭代,迭代的过程就是有个类似于异步的思想 就是在打印取值的时候回去generate_num方法中去,然后执行到yield时会将yield给后面的值返回,在这里有异步到print去打印这个值,然后执行接下来的代码,而下一次取值的时候会从yield下一句开始执行接下来的代码,但是yield里有个方法可以实现两个异步模块的通信,就是send方法

2.yield的send方法

就是我们send是可以往生成器传递参数的

代码演示:

def generate_num():
    count = 0
    while count < 10:
        ret = yield count
        print(ret)
        count += 1

obj_generate = generate_num()   # 创建生成器对象

num = next(obj_generate)   # 这里的next是个迭代方法,意是去生成器取一个值
print(num)

str = '传参'
num1 = obj_generate.send(str)  # 也会正常返回迭代的数,只不过多了一个功能
print(num1)
'''
0
传参
1
'''

从结果来看确实验证了,代码是从print(num1)跳到print(ret),也验证了send方法可以传递参数

2.greenlet简介

greenlet是对yield的封装我们先用一个demo来看看他的用法

代码演示:

# 1.导包
from greenlet import greenlet


def print_a():
    a = 0
    while a <= 1 
        print('-----a-----')
        gr2.switch()        # 启动print_b
        a += 1

def print_b():
    b = 0
    while b <= 1 
        print('-----b-----')
        gr1.switch()
        b += 1

gr1 = greenlet(print_a)   # 创建两个对象
gr2 = greenlet(print_b)

gr1.switch()     # 启动print_a

'''
-----a-----
-----b-----
-----a-----
-----b-----
'''

代码的思路和yield差不多,先创建两个生成器对象,switch()直接跳到相应的生成器方法里,然后直到遇到下一个switch()再次跳跃,当不是初次进入生成器的时候会从上一次跳出的的下一段代码开始执行,值得注意的是这里的结果有点像多任务了,就是两个模块交替进行

三.gevent简介

gevnet是在greenlet的基础上再次迭代封装,我们先写个demo初步了解一下

代码演示:

# 导包 
import gevent


def gevent_print(count):
    for num in range(count):
        print(num)

g1 = gevent.spawn(gevent_print, 3)     # 创建gevent对象
g2 = gevent.spawn(gevent_print, 3)
g3 = gevent.spawn(gevent_print, 3)

g1.join()
g2.join()
g3.join()
'''
0
1
2
0
1
2
0
1
2
'''

这里的spawn函数指定要传一个生成数的对象,第二个参数是指定要生成多少个数,join方法是启动的的标志,表示开始生成,但是这不是我们最终想要的结果,因为我们说过协程也是可以完成多任务的就像greenlet交替输出,但要看greenlet原理的话,又好像有点费时,就是需要一个任务完成之后跳转出去之后那个函数一直再等待switch调他,我们想再等待时间里也去干点别的,这才是多任务,gvent就解决了这个,就是在一个方法好事的时候会自动给调另一个gevent生成的对象,高效利用时间,就是gevent在遇到延时操作,或者阻塞操作的时候会自动开启另一个子线程运行另一个gevent生成的对象,但它不需要time.sleep这样的延时哦,在gevent里有他自己的延时操作是gevent.time.sleep

代码演示;

#导包
import gevent
import time
from gevent import monkey 


# def gevent_print(count):
#    for num in range(count):
#       print(num)
#       gevent.time.sleep(0.5)  

monkey.petch_all()    # 这里是给gevnet打补丁

def gevent_print(count):
    for num in range(count):
        print(num)
        time.sleep(0.5)

g1 = gevent.spawn(gevent_print, 3)     # 创建gevent对象
g2 = gevent.spawn(gevent_print, 3)
g3 = gevent.spawn(gevent_print, 3)

g1.join()
g2.join()
g3.join()
'''
0
0
0
1
1
1
2
2
2
'''

看我们需要的多任务结果呈现了,就是如果一个方法需要等待,我们可以将这个等待的时间转交给另一个对象,让它完成自己的事,网络通信上的那些阻塞函数也是,我们去等待接收client发送请求的过程,我们也可以去个client发送东西,而这个补丁是因为我们的每一个延时操作或者阻塞操作都需要gevent模块里的特定相应方法,所以每个操作前都得加gevent,就像gevent.time.sleep,但如果这样的代码有很多,几千行,你一个一个找?O.o?所以我们打上补丁之后就不用找着去添加,它自己会给那些延时或阻塞操作前面加上gevent(编译时)

最终我们再介绍一个是代码更简洁的方法就是

gevent.joinall([gevent.spawn(gevent_print, 3)
                gevent.spawn(gevent_print, 3)
                gevent.spawn(gevent_print, 3)
])

 就是在方法里直接传递实例对象列表,之后会一个一个执行(没有阻塞延时)

四,总结

其实说那么多,就是想要实现协程多任务,我们起初通过yield生成一些数,暂停转向别处执行代码,并不释放方法里的资源,微线程;greenlet简单在方法中跳转,貌似是个多任务,但有时太耗时了,直到我们提到gevent解决了耗时的时候别的任务在等待的尴尬局面最终实现类似多任务,协程是完成多任务python独有的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值