协程的概念级描述(与线程对比):转自知乎 链接
线程有两个必须要处理的问题:一是碰着阻塞式IO会导致整个进程被挂起;
二是由于缺乏时钟阻塞,进程需要自己拥有调度线程的能力。
如果一种实现使得每个线程需要自己通过调用某个方法,主动交出控制权。那么我们就称这种线程是协作式的,即是协程。
在Python中关于协程的实现方式有三种:
- 最初的生成器变形yield/send
- 引入@asyncio.coroutine和yield from
- 在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!
简单的async
和await
使用描述:
async
和await
是针对coroutine的新语法,要使用新的语法,只需要做两步简单的替换:
- 把
@asyncio.coroutine
替换为async
; - 把
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()
需要注意的是async
和await
只能用在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