zoukankan      html  css  js  c++  java
  • python_协程、从生成器到协程的发展历程、gevent第三方库实现协程、内置asycio实现协程

    一:协程

    概念:  

    协程:
    1)并发:JMeter并发100个请求。
    2)并行:2个进程分别在2个cpu上并行运行
    3)同步:IO操作,耗时,等待操作完毕
    4)异步:不等待操作完毕
    5)并发是实现异步
    实现异步(并发)的方法有:多线程、协程
    (1)多线程:CPU调度多个线程 (由内核决定的)
    (2)协程:开发人员调度多个任务(开发人员:指的是用户)
    举栗:有两个函数 work1() ,work2(),当work1阻塞的时候运行work2,work2阻塞的时候运行work1
    要实现这个例子:需要有 1)挂起当前状态(暂停) 2)激活挂起的状态(恢复) 的能力

    核心思想:  

    协程的核心思想:
    为了实现异步io
    若干个协程任务,当某个任务遇到阻塞时,自动切换到非阻塞的任务上
    阻塞: io阻塞。如:input("请输入一个数: "),磁盘io(写数据是需要时间的),网络io(网络请求数据时需要时间的)
    用户态:切换不需要CPU调度
    核心态:线程切换,进程切换,核心态, 切换需要cpu调度

    二。从生成器到协程:python在3.5版本之前是没有协程这个概念的,生产器是在python2.3版本中引入的,使用生成器实现协程是在 python2.5 可以进行的。

    发展历程:

      

    从生成器到协程:从Python2到Python3,协程经历了翻天覆地的变化。
    简单的生成器:
    https:www.python.org/dev/peps/pep-0255/
    Python2.3中,加入了新的关键字:yield
    在PE255中,引入了yield表达式
    规定yield语句只能在函数中使用。包含yield语句的函数被称为生成器函数
    当执行到yield语句时,函数的状态会被冻结(挂起所有状态,如:局部变量、指令指针、堆栈状态等),以便下载
    next时恢复状态继续执行。
    通过生成器实现协程:
    协程的底层架构是在PEP 342中定义,在Python2.5实现的。
    实现思想:使用yield挂起生成器,使用send方法激活生成器就具备实现协程功能
    执行generator.send(None) 完全等同于调用生成器的 next方法。使用其他参数调用send也有同样的效果, 的是,当前生成器表达式产生的值会不一样。
    参考资料:PEP 342 Coroutines via Enhanced Generators https://www.python.org/dev/peps/pep-0342/

    协程的演变:
    Python3.3增加了 yield from 语法,使用调用嵌套生成器变得简单
    举栗:
    def f():
    yield from [1,2,3]
    Python3.5 加入了关键字 async 和 await,将生成器和协程全部分开
    参考资料:
    PEP 380 Syntax for Delegating to a Subgenerator https://www.python.org/dev/peps/pep-0380/
    PEP 525 Asynchronous Generators https://www.python.org/dev/peps/pep-0525/

    生成器实现协程:

      

    """
    也就是使用生成器实现多任务
    """

    import time

    def work1():
    for i in range(5):
    print("work1:函数运行中")
    time.sleep(1)
    yield

    def work2():
    for i in range(5):
    print("work2:函数运行中")
    time.sleep(1)
    yield


    def calc_time(func):
    def wrap(*args, **kwargs):
    start = time.time()
    func(*args, **kwargs)
    end = time.time()
    print(f"耗时{end - start:.2f}秒")
    return wrap

    @calc_time
    def main():
    g1 = work1()
    g2 = work2()
    while True:
    try:
    next(g1) #使用迭代控制实现协程
    next(g2)
    except StopIteration:
    break
    if __name__ == '__main__':
    main()

      

    运行结果:

    二。gevent

    实现方法一:通过gevent.time()实现协程

    """
    也就是使用生成器实现多任务:
    注意:
    1.gevent 如果不适用阻塞,主程序结束,子程序也会结束(子程序==线程)
    """
    #1,gevent 协程方法一,使用gevent.time()实现协程
    import time
    import gevent
    def work1():
    for i in range(5):
    print("work1:函数运行中")
    gevent.sleep(1)


    def work2():
    for i in range(5):
    print("work2:函数运行中")
    gevent.sleep(1)


    def calc_time(func):
    def wrap(*args, **kwargs):
    start = time.time()
    func(*args, **kwargs)
    end = time.time()
    print(f"耗时{end - start:.2f}秒")
    return wrap

    @calc_time
    def main():
    g1 = gevent.spawn(work1)
    g2 = gevent.spawn(work2)
    g1.join()
    g2.join()


    if __name__ == '__main__':
    main()

    运行结果:

    实现方法二:通过打补丁的方式实现协程(导入monkey模块中的patch_all()方法)

    """
    也就是使用生成器实现多任务:
    注意:
    1.gevent 如果不适用阻塞,主程序结束,子程序也会结束(子程序==线程)
    """
    #1,gevent 协程方法一,使用gevent.time()实现协程
    import time
    import gevent
    from gevent import monkey
    monkey.patch_all()

    #2.gevent,协程使用方法二 打补丁,导入monkey模块中的patch_all()方法 。导入: from gevent import monkey; monkey.patch_all()
    def work3():
    for i in range(5):
    print("work3:函数运行中")
    time.sleep(1)


    def work4():
    for i in range(5):
    print("work4:函数运行中")
    time.sleep(1)


    def calc_time(func):
    def wrap(*args, **kwargs):
    start = time.time()
    func(*args, **kwargs)
    end = time.time()
    print(f"耗时{end - start:.2f}秒")
    return wrap


    @calc_time
    def main2():
    g3 = gevent.spawn(work3)
    g4 = gevent.spawn(work4)
    g3.join()
    g4.join()

    if __name__ == '__main__':
    main2()

    运行结果:

    三。asycio

    """
    python3.5之后可用
    """
    import time
    import asyncio #异步IO库,单线程实现并发 --协程


    #async 关键字包裹 await 关键字结束

    async def work1():
    for i in range(5):
    print(f"work1:函数运行")
    await asyncio.sleep(1)


    async def work2():
    for i in range(5):
    print(f"work2:函数运行")
    await asyncio.sleep(1)


    def calc_time(func):
    def wrap(*args, **kwargs):
    start = time.time()
    func(*args, **kwargs)
    end = time.time()
    print(f"耗时{end - start:.2f}秒")
    return wrap


    async def main():
    task1 = asyncio.create_task(work1()) #任务一
    task2 = asyncio.create_task(work2()) # 任务二
    await task1
    await task2
    if __name__ == '__main__':
    start = time.time()
    asyncio.run(main())
    end = time.time()
    print(f"耗时{end - start:.2f}秒")

    运行结果:

    爱折腾的小测试
  • 相关阅读:
    AESUtil_1
    ELK配置
    Centos7上安装docker
    Excel大批量数据导出
    Redis5.0.6安装完整步骤
    idea远程打断点
    [HNOI2016] 序列
    [TJOI2017] 异或和
    洛谷 P4933 大师
    洛谷 P1950 长方形_NOI导刊2009提高(2)
  • 原文地址:https://www.cnblogs.com/newsss/p/14618520.html
Copyright © 2011-2022 走看看