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()
    
  • 相关阅读:
    使用FolderBrowserDialog组件选择文件夹
    使用OpenFileDialog组件打开多个文
    使用OpenFileDialog组件打开对话框
    获取弹出对话框的相关返回值
    PAT 甲级 1139 First Contact (30 分)
    PAT 甲级 1139 First Contact (30 分)
    PAT 甲级 1138 Postorder Traversal (25 分)
    PAT 甲级 1138 Postorder Traversal (25 分)
    PAT 甲级 1137 Final Grading (25 分)
    PAT 甲级 1137 Final Grading (25 分)
  • 原文地址:https://www.cnblogs.com/amize/p/14599994.html
Copyright © 2011-2022 走看看