Python-协程yield/gevent的使用

(协程)使用yield生成器实现多任务
"""
线程-进程-携程 之间消耗的资源
进程(申请各种内存cpu至少一个线程等等资源)>线程(多一个线程)>携程(还是在当前单线程下运行)
并发与并行的概念
并行:在cpu中多个核分别执行不同的任务为并行
并发:在一个线程或者一个cpu中交替执行任务的模式为并发


模拟同事执行多个任务
"""
import time


def run1():
    while True:
        print("----------1-------------")
        time.sleep(0.1)
        """
        使用yield修改当前方法为一个特殊的迭代器(生成器) 每次使用next()调用当前方法时 走到yield 就会暂停当前方法 直到下次调用next() 方法
        """
        yield


def run2():
    while True:
        print("----------2-------------")
        time.sleep(0.1)
        yield


def run3():
    while True:
        print("----------3-------------")
        time.sleep(0.1)
        yield


if __name__ == '__main__':
    r1 = run1()
    r2 = run2()
    r3 = run3()
    while True:
        next(r1)
        next(r2)
        next(r3)

(高级协程)使用gevent实现多任务
"""
携程依赖于线程 线程依赖于进程
携程的目的是利用在该线程中空闲的时间 完成一些其他的相对并不重要的任务
最原始的yield->greenlet->gevent  到现在的gevent都是对前面函数方法的封装
"""
import time
import gevent
from gevent import monkey

"""
一下代码为携程的日常使用方式
"""

# 将程序中用到的耗时的错误的代码更换为gevent中自己实现的代码
# 会扫描当前类中的所有代码 把time.sleep() 这类的代码修改成fevent相对应的代码
monkey.patch_all()


def f1(n):
    for i in range(n):
        print("当前携程[{}] ->[{}]".format(gevent.getcurrent(), i))
        # gevent.sleep(0.5)
        time.sleep(0.5)


if __name__ == '__main__':
    gevent.joinall([
        gevent.spawn(f1, 4),
        gevent.spawn(f1, 4),
        gevent.spawn(f1, 4),
        gevent.spawn(f1, 4),
        gevent.spawn(f1, 4)
    ])
    # g1 = gevent.spawn(f1, 4)
    # g2 = gevent.spawn(f1, 4)
    # g3 = gevent.spawn(f1, 4)
    # g4 = gevent.spawn(f1, 4)
    # g1.join()
    # g2.join()
    # g3.join()
    # g4.join()

01实现一个可以迭代的对象
"""
手动实现一个自己的迭代器

迭代器个人定义:
一个class类中 拥有 __iter__ 和__next__ 方法 就可以称之为这个类为迭代器

# 这里需要注意 Iterable 判断是否可以迭代使用Iterable
# 这里需要注意 判断是否可以使用 next() 迭代 需要使用到Iterator
凡是可以for循环的,都是Iterable
凡是可以next()的,都是Iterator
集合数据类型如list,truple,dict,str,都是Itrable不是Iterator,但可以通过iter()函数获得一个Iterator对象
Python中的for循环就是通过next实现的
"""
from collections.abc import Iterable, Iterator


class ClassMate(object):
    def __init__(self, list1):
        self.names = list1
        self.current_num = 0

    # 1.需要创建一个 迭代器方法 传入一个迭代器
    def __iter__(self):
        return self

    def add(self, name):
        self.names.append(name)

    def __next__(self):
        if self.current_num < len(self.names):
            r = self.names[self.current_num]
            self.current_num += 1
            return r
        # 如果不发出终止信号 for 会一直迭代运行 返回None
        # 所以这里需要 发出一个终止的信号
        else:
            raise StopIteration


if __name__ == '__main__':
    c1 = ClassMate([])
    c1.add("张三")
    c1.add("李四")
    c1.add("王五")

    # 判断该对象是否是一个可迭代对象
    print("ClassMate是否是一个可迭代对象[{}]".format(isinstance(c1, Iterable)))

    for i in c1:
        print(i)

02实现斐波那契数列
"""
通过自定义迭代器
实现一个斐波那契数列
a,b=b,a+b  先运算再赋值  a=1 b=2  就是 a,b=2,1+2  就是 a,=2  b=3
"""


class FbnqslIter(object):
    def __init__(self, num):
        self.num = num
        self.current_num = 0
        self.a = 0
        self.b = 1

    def __iter__(self):
        return self

    def __next__(self):
        while self.current_num < self.num:
            rest = self.a
            self.a, self.b = self.b, self.a + self.b
            self.current_num += 1
            return rest
        raise StopIteration


if __name__ == '__main__':
    for i in FbnqslIter(15):
        print(i)
03使用生成器实现斐波那契数列
"""
使用生成器创建一个斐波那契数列
相关地址:https://blog.csdn.net/mieleizhi0522/article/details/82142856/
"""


def fbona(num):
    """
    正常情况下 fbona(num) 是一个函数  但是当一个函数中出现了yield 时 该数据就是一个特殊的迭代器了  也就是生成器
    程序代码每次运行到 yield 时就等于是在next() 方法下 return一个值且暂停fbona() 方法,直到下次调用next()方法时 启动
    :param num:
    :return:
    """
    a, b = 0, 1
    current_num = 0
    while current_num < num:
        yield a
        a, b = b, a + b
        current_num += 1
    return "ok....."


if __name__ == '__main__':
    f = fbona(20)
    while True:
        try:
            print(next(f))
        except StopIteration as s:
            print(s.value)
            break

04生成器中使用seed进行传值
"""

同yield  seed() 效果是一样的 但是yield是不会传入值 seed() 可以在函数中yield调用后 返回一个seed 传入的值
在生成器业务中 如果有需要传值 或者需要临时的根据各种外部条件对业务逻辑进行调整的时候
这里就需要用到seed, 需要注意的是在第一次循环时需要使用seed的时候seed() 里面不能传入值  否则会报错
"""


def fbnqsl(num):
    current_num, a, b = 0, 0, 1

    while current_num < num:
        ret = yield a
        if ret is not None:
            print("当前seed传入的值是[{}]".format(ret))
        a, b = b, a + b
        current_num += 1


if __name__ == '__main__':
    f = fbnqsl(20)
    print(next(f))
    print(f.send(123))
    print(f.send(222))
    for i in f:
        print(i)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值