python基础-yield与装饰器、yield并发切换(非io)、greenlet实现切换(非io)

yield结合装饰器(无返回值)

def deco(func): 
    def wrapper():
        yie = func()
        print(type(yie))
        ret = next(yie)
        return yie
    return wrapper
@deco
def foo():
    while True:
        x = yield
        print("x-->",x)

g = foo()
g.send(1)
g.send(2)

输出如下:

<class 'generator'>
x--> 1
x--> 2

以上代码的大概意思是:
@deco是装饰器的语法糖模式,foo()是执行deco函数中wrapper函数,yie = func()是返回一个generator生成器,然后next(yie),这里原因是g.send不能用在第一个触发生成器 ,然后在main线程里面,g = foo()返回一个生成器,然后g.send(1) g.send(2)就输出foo()函数的打印输出

yield结合装饰器(有返回值)

我们在来看一个yield带返回值的

print("--------------------")
def deco(func):
    def wrapper():
        res = func()
        next(res)
        return res
    return wrapper
@deco
def foo():
    food_list = []
    while True:
        food = yield food_list  #返回添加food的列表
        food_list.append(food)
        print("elements in foodlist are:",food)
g = foo()
print(g.send('苹果'))
print(g.send('香蕉'))
re = g.send('菠萝')

输出如下:

E:\python\python_sdk\python.exe E:/python/py_pro/python.py
--------------------
elements in foodlist are: 苹果
['苹果']
elements in foodlist are: 香蕉
['苹果', '香蕉']
elements in foodlist are: 菠萝

Process finished with exit code 0

以上的代码g.send(‘xx”)返回一个food_list,然后输出列表信息即可

yield实现并发效果

以上的yield是跟装饰器结合使用,我们来看看yield能不能实现,程序遇到io实现切换?
以下的例子是生产者生产数据,消费者消费数据


#基于yield并发执行
import time
def consumer():
    '''任务1:接收数据,处理数据'''
    while True:
        x=yield
        print("consumer拿到数据了x:",x)

def producer():
    '''任务2:生产数据'''
    g=consumer()
    next(g)
    for i in range(10):
        print("producer生产数据了",i)
        g.send(i)

start=time.time()
#基于yield保存状态,实现两个任务直接来回切换,即并发的效果
#PS:如果每个任务中都加上打印,那么明显地看到两个任务的打印是你一次我一次,即并发执行的.
producer()

stop=time.time()
print(stop-start)

代码输出:

E:\python\python_sdk\python.exe E:/python/py_pro/python.py
producer生产数据了 0
consumer拿到数据了x: 0
producer生产数据了 1
consumer拿到数据了x: 1
producer生产数据了 2
consumer拿到数据了x: 2
producer生产数据了 3
consumer拿到数据了x: 3
producer生产数据了 4
consumer拿到数据了x: 4
producer生产数据了 5
consumer拿到数据了x: 5
producer生产数据了 6
consumer拿到数据了x: 6
producer生产数据了 7
consumer拿到数据了x: 7
producer生产数据了 8
consumer拿到数据了x: 8
producer生产数据了 9
consumer拿到数据了x: 9
0.0

Process finished with exit code 0

基于yield保存状态,实现两个任务直接来回切换,即并发的效果
PS:如果每个任务中都加上打印,那么明显地看到两个任务的打印是你一次我一次,即并发执行的.

yield不能实现io切换

yield是实现了并发的效果,但是它能实现,在io阻塞,进行任务间切换么?我们来看一个例子

import time
def consumer():
    '''任务1:接收数据,处理数据'''
    while True:
        x=yield
        print("consumer拿到数据了x:", x)

def producer():
    '''任务2:生产数据'''
    g=consumer()
    next(g)
    for i in range(3):
        print("producer生产数据了")
        g.send(i)
        time.sleep(2)

start=time.time()
producer() #并发执行,但是任务producer遇到io就会阻塞住,并不会切到该线程内的其他任务去执行

stop=time.time()
print(stop-start)
producer生产数据了
consumer拿到数据了x: 0
(有io阻塞)
producer生产数据了
consumer拿到数据了x: 1
(有io阻塞)
producer生产数据了
consumer拿到数据了x: 2

6.001317262649536

通过输出效果显示,并不能

greenlet任务切换

如果我们在单个线程内有20个任务,要想实现在多个任务之间切换,使用yield生成器的方式过于麻烦(需要先得到初始化一次的生成器,然后再调用send。。。非常麻烦),而使用greenlet模块可以非常简单地实现这20个任务直接的切换

greenlet只是提供了一种比generator更加便捷的切换方式,当切到一个任务执行时如果遇到io,那就原地阻塞,仍然是没有解决遇到IO自动切换来提升效率的问题。

单纯的切换(在没有io的情况下或者没有重复开辟内存空间的操作),反而会降低程序的执行速度

from greenlet import greenlet

def eat(name):
    print('%s eat 1' %name)
    g2.switch('aaa')
    print('%s eat 2' %name)
    g2.switch()
def play(name):
    print('%s play 1' %name)
    g1.switch()
    print('%s play 2' %name)

g1=greenlet(eat)
g2=greenlet(play)

g1.switch('safly')#可以在第一次switch时传入参数,以后都不需要

输出如下:

E:\python\python_sdk\python.exe E:/python/py_pro/python.py
safly eat 1
aaa play 1
safly eat 2
aaa play 2

Process finished with exit code 0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值