zoukankan      html  css  js  c++  java
  • python的协程(Coroutine)思想【生成器】

    https://www.jianshu.com/p/84df78d3225a#yield-from表达式

    1. GIL
      全局解释器锁(英语:Global Interpreter Lock,缩写GIL),是计算机程序设计语言解释器用于同步线程的一种机制,它使得任何时刻仅有一个线程在执行。
      即便在多核心处理器上,使用 GIL 的解释器也只允许同一时间执行一个线程。

    2. 协程
      协程,又称微线程,纤程,英文名Coroutine。协程的作用,是在执行函数A时,可以随时中断,去执行函数B,然后中断继续执行函数A(可以自由切换)。
      但这一过程并不是函数调用(没有调用语句),这一整个过程看似像多线程,然而协程只有一个线程执行.

    Python3.4之前,官方没有对协程的支持,存在一些三方库的实现,比如gevent和Tornado。
    3.4之后就内置了asyncio标准库,官方真正实现了协程这一特性。而Python对协程的支持,是通过Generator实现的,协程是遵循某些规则的生成器。

    1. 生成器:
    
    def test():
        print("generator start")
        n = 1
        while True:
            yield_expression_value = yield n
            print("yield_expression_value = %d" % yield_expression_value)
            n += 1
    
    
    # ①创建generator对象
    generator = test()
    print(type(generator))
    
    print("
    ---------------
    ")
    
    # ②启动generator
    next_result = generator.__next__()
    print("next_result = %d" % next_result)
    
    print("
    ---------------
    ")
    
    # ③发送值给yield表达式
    send_result = generator.send(666)
    print("send_result = %d" % send_result)
    
    
    '''
    1. __next__()方法: 作用是启动或者恢复generator的执行,相当于send(None)
    2. send(value)方法:作用是发送值给yield表达式。启动generator则是调用send(None)
    3. 生成器启动或恢复执行一次,将会在yield处暂停。上面的第②步仅仅执行到了yield n,并没有执行到赋值语句,到了第③步,生成器恢复执行才给yield_expression_value赋值。
    '''
    
    
    1. 生产者消费者模型(整个流程无锁,由一个线程执行,produce和consumer协作完成任务,所以称为“协程”,而非线程的抢占式多任务。)
    def consumer():
        print("[CONSUMER] start")
        r = 'start'
        while True:
            n = yield r
            if not n:
                print("n is empty")
                continue
            print("[CONSUMER] Consumer is consuming %s" % n)
            r = "200 ok"
    
    
    def producer(c):
        # 启动generator
        start_value = c.send(None)
        print(start_value)
        n = 0
        while n < 3:
            n += 1
            print("[PRODUCER] Producer is producing %d" % n)
            r = c.send(n)
            print('[PRODUCER] Consumer return: %s' % r)
        # 关闭generator
        c.close()
    
    
    # 创建生成器
    c = consumer()
    # 传入generator
    producer(c)
    
    1. yield from 思想
    
    #  1
    # 子生成器
    def test(n):
        i = 0
        while i < n:
            yield i
            i += 1
    
    # 委派生成器
    def test_yield_from(n):
        print("test_yield_from start")
        yield from test(n)
        print("test_yield_from end")
    
    
    for i in test_yield_from(3):
        print(i)
    '''
    test_yield_from start
    0
    1
    2
    test_yield_from end
    '''
    
    
    #  2
    # 如果上面的test_yield_from函数中有两个yield from语句,将串行执行。test_yield_from函数改写成这样:
    
    def test_yield_from(n):
        print("test_yield_from start")
        yield from test(n)
        print("test_yield_from doing")
        yield from test(n)
        print("test_yield_from end")
    将输出:
    '''
    test_yield_from start
    0
    1
    2
    test_yield_from doing
    0
    1
    2
    test_yield_from end
    '''
    
    # yield from起到的作用相当于下面写法的简写形式 (它还帮我们处理了异常之类的)
    for item in test(n):
        yield item
    
    
    
    
    1. Python3.4中,使用@asyncio.coroutine 和yield from 实现协程
    
    # @asyncio.coroutine源码简化
    
    import functools
    import types
    import inspect
    
    def coroutine(func):
        # 判断是否是生成器
        if inspect.isgeneratorfunction(func):
            coro = func
        else:
            # 将普通函数变成generator
            @functools.wraps(func)
            def coro(*args, **kw):
                res = func(*args, **kw)
                res = yield from res
                return res
        # 将generator转换成coroutine
        wrapper = types.coroutine(coro)
        # For iscoroutinefunction().
        wrapper._is_coroutine = True
        return wrapper
    
    
    # 我们来使用 @asyncio.coroutine 和 yield from:
    import asyncio
    
    @asyncio.coroutine
    def compute(x, y):
        print("Compute %s + %s ..." % (x, y))
        yield from asyncio.sleep(1.0)
        return x + y
    
    @asyncio.coroutine
    def print_sum(x, y):
        result = yield from compute(x, y)
        print("%s + %s = %s" % (x, y, result))
    
    loop = asyncio.get_event_loop()
    print("start")
    # 中断调用,直到协程执行结束
    loop.run_until_complete(print_sum(1, 2))
    print("end")
    loop.close()
    
    '''
    start
    Compute 1 + 2 ...
    1 + 2 = 3
    end
    '''
    
    
    

    1. Python3.5开始引入async/await语法,async/await实际上只是@asyncio.coroutine和yield from的语法糖:
      把@asyncio.coroutine替换为async
      把yield from替换为await
    import asyncio
    
    async def compute(x, y):                   # @asyncio.coroutine替换为async
        print("Compute %s + %s ..." % (x, y))
        await asyncio.sleep(1.0)               # 把yield from替换为await
        return x + y
    
    
    async def print_sum(x, y):                # @asyncio.coroutine替换为async
        result = await compute(x, y)          # 把yield from替换为await
        print("%s + %s = %s" % (x, y, result))
    
    
    loop = asyncio.get_event_loop()
    print("start")
    loop.run_until_complete(print_sum(1, 2))
    print("end")
    loop.close()
    
    
    1. asyncio中Future的例子
    import asyncio
    
    future = asyncio.Future()
    
    async def coro1():
        print("wait 1 second")
        await asyncio.sleep(1)
        print("set_result")
        future.set_result('data')
    
    
    async def coro2():
        result = await future
        print(result)
    
    # 1.
    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait([
        coro1()
        coro2()
    ]))
    loop.close()
    
    # 2. 结果和1 一样,await future 必须要等待future.set_result('data')后才能够结束。将coro2()作为第二个协程可能体现得不够明显,可以将协程的调用改成这样:
    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait([
        # coro1(),
        coro2(),
        coro1()
    ]))
    loop.close()
    
  • 相关阅读:
    form表单中name和id区别
    为什么我做网站开发不使用前端框架
    设置GridView表头的背景图片
    input文本框隐藏边框
    如何在asp.net页面使用css和js
    HTML与XHTML的差别
    asp.net实现关闭当前网页功能
    asp.net判断文件或文件夹是否存在
    asp.net自定义错误页面
    asp.net中textbox获得焦点后清空默认文本
  • 原文地址:https://www.cnblogs.com/amize/p/14599994.html
Copyright © 2011-2022 走看看