zoukankan      html  css  js  c++  java
  • Python 进阶 之 协程

    协程的概念级描述(与线程对比):转自知乎 链接

      线程有两个必须要处理的问题:一是碰着阻塞式IO会导致整个进程被挂起;

                    二是由于缺乏时钟阻塞,进程需要自己拥有调度线程的能力。

      如果一种实现使得每个线程需要自己通过调用某个方法,主动交出控制权。那么我们就称这种线程是协作式的,即是协程。

    在Python中关于协程的实现方式有三种:

    1. 最初的生成器变形yield/send
    2. 引入@asyncio.coroutine和yield from
    3. 在Python3.5版本中引入async/await关键字

    以下代码均在Centos 7 Python3.6调试通过!

    简单的yield使用描述:

    def fun():
        index = 0
        while True:
            yield index
            index += 1
            if index > 3 :
                break
    for i in fun():
        print (i)
    输出:0 1 2 3

    在此例中yield做的事是:

      1:将函数fun的返回值设定为一个生成器

      2:每次运行至yield index 时会将index的值作为生成器的下一个元素返回值for循环并且被赋值给变量i,用print输出出来

    简单的yield/send使用描述:

    def fun():
        index = 0
        while True:
            value = yield index
            print ("value=" + str(value))
            print ("index=" + str(index))
            index += 1
            if index > 3 :
                break
    funobj = fun()
    print (type(funobj))
    print ("next=" + str(next(funobj)))
    for i in funobj:
        print ("i=" + str(i))
        try:
            funobj.send(i+100)
        except StopIteration:
            print("it's stop")
    输出:

    <class 'generator'>
    next=0
    value=None
    index=0
    i=1
    value=101
    index=1
    value=None
    index=2
    i=3
    value=103
    index=3
    it's stop

    不是很精通,因此代码有点乱。

    解释:

      首先声明了fun函数,并将fun赋给了对面funobj,funobj是一个迭代器。next(funobj)初始化并启动迭代器,程序开始运行fun函数至value = yield index(第一次)结束,yield返回了第一个index值0 next=0

      for i in funobj:启动迭代器,因此此时send还未传值,因此value和next都是空,value=None index=0 程序运行fun函数至value = yield index(第二次)结束,yield返回了第二个index值1 i=1

      注意之后send发送了值101,for再次启动迭代器,从yield启动时捕获到此值101,value=101 index=101。此后类似。

      迭代器结束时会捕获到 StopIteration异常,将此捕获并输出出来 it's stop

    简单的yield/send使用描述:

      yeild from语法就是将生成器函数中包括yield语句的部分逻辑封装到一个子生成器函数中。然后在子生成器函数外面可以做一些其他的业务逻辑。整个生成器函数(包括子生成器函数)对外就是一个生成器函数。

    def fun():
        index = 0
        while True:
            value = yield index
            print ("value=" + str(value))
            print ("index=" + str(index))
            index += 1
            if index > 3 :
                break
    
    def fun2():
        print ("before ")
        yield from fun()
        print ("end ")
    
    funobj = fun2()
    print (type(funobj))
    print ("next=" + str(next(funobj)))
    for i in funobj:
        print ("i=" + str(i))
        try:
            funobj.send(i+100)
        except StopIteration:
            print("it's stop")

    输出:

    <class 'generator'>
    before 
    next=0
    value=None
    index=0
    i=1
    value=101
    index=1
    value=None
    index=2
    i=3
    value=103
    index=3
    end 
    it's stop

     简单的asyncio.coroutine使用描述:(参考自廖雪峰的官方网站

    @asyncio.coroutine通过装饰器调用,作用是把一个generator标记为coroutine类型:

    import asyncio
    
    @asyncio.coroutine
    def hello():
        print("Hello world!")
        # 异步调用asyncio.sleep(1):
        r = yield from asyncio.sleep(1)
        print("Hello again!")
    
    # 获取EventLoop:
    loop = asyncio.get_event_loop()
    # 执行coroutine
    loop.run_until_complete(hello())
    loop.close()

    输出:

    Hello world!
    Hello again!

    简单的asyncawait使用描述:

      asyncawait是针对coroutine的新语法,要使用新的语法,只需要做两步简单的替换:

    1. @asyncio.coroutine替换为async
    2. yield from替换为await

      示例代码:

    import asyncio
    
    async def hello():
        print("Hello world!")
        r = await asyncio.sleep(1)
        print("Hello again!")
    
    # 获取EventLoop:
    loop = asyncio.get_event_loop()
    # 执行coroutine
    loop.run_until_complete(hello())
    loop.close()

      需要注意的是asyncawait只能用在Python 3.5以及后续版本,如果使用3.4版本,则仍需使用asyncio.coroutine和yield from方案。

      示例可能出现的报错如下:

    [root@jans test]# python3.6 c.py 
    Hello world!
    Hello again!
    [root@jans test]# python3.4 c.py 
      File "c.py", line 3
        async def hello():
                ^
    SyntaxError: invalid syntax
  • 相关阅读:
    第一节,Django+Xadmin打造上线标准的在线教育平台—创建用户app,在models.py文件生成3张表,用户表、验证码表、轮播图表
    Tensorflow 错误:Unknown command line flag 'f'
    Python 多线程总结
    Git 强制拉取覆盖本地所有文件
    Hive常用函数 傻瓜学习笔记 附完整示例
    Linux 删除指定大小(范围)的文件
    Python 操作 HBase —— Trift Trift2 Happybase 安装使用
    梯度消失 梯度爆炸 梯度偏置 梯度饱和 梯度死亡 文献收藏
    Embedding 文献收藏
    深度学习在CTR预估中的应用 文献收藏
  • 原文地址:https://www.cnblogs.com/JansXin/p/7841369.html
Copyright © 2011-2022 走看看