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()
原文地址:https://www.cnblogs.com/amize/p/14599994.html