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=0

   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