协程(Coroutine),又称微线程,纤程。一般咱们认为线程是轻量级的进程,所以咱们也把协程理解为轻量级的线程即微线程。python
协程的做用是在执行函数A时能够随时中断去执行函数B,而后中断函数B继续执行函数A(能够自由切换)。这里的中断,不是函数的调用,而是有点相似CPU的中断。这一整个过程看似像多线程,然而协程只有一个线程执行。多线程
例:并发
def simple_coroutine(): print('-> start') x = yield print(x) print('-> end') #主线程 sc = simple_coroutine() # 可使用sc.send(None),效果同样 next(sc) #预激 sc.send('go')
执行结果以下:异步
-> start go -> end 抛出StopIteration
simple_coroutine()
是一个生成器,由next(sc)
预激,启动协程,执行到第一个yield中断send()
方法给yield传入参数,继续执行async
GEN_CLOSED:执行结束函数
终止协程的一种方式:发送某个哨符值,让协程退出。内置的 None 和Ellipsis 等常量常常用做哨符值oop
asyncio
是Python3.4版本引入的标准库,直接内置了对异步IO的支持。asyncio
的异步操做,须要在coroutine
中经过yield from
完成。
例:性能
import asyncio @asyncio.coroutine def test(i): print('test_1', i) r = yield from asyncio.sleep(1) print('test_2', i) loop = asyncio.get_event_loop() tasks = [test(i) for i in range(1,3)] loop.run_until_complete(asyncio.wait(tasks)) loop.close()
@asyncio.coroutine
把一个generator
标记为coroutine
类型,而后就把这个coroutine
扔到EventLoop
中执行。test()
会首先打印出test_1yield from
语法可让咱们方便地调用另外一个generator
。因为asyncio.sleep()
也是一个coroutine
,因此线程不会等待asyncio.sleep()
,而是直接中断并执行下一个消息循环。asyncio.sleep()
返回时,线程就能够从yield from
拿到返回值(此处是None)asyncio.sleep(1)
当作是一个耗时1秒的IO操做,在此期间主线程并未等待,而是去执行EventLoop
中其余能够执行的coroutine
了,所以能够实现并发执行结果以下:线程
test_1 1 test_1 2 test_2 1 test_2 2
当yield from
后面加上一个生成器后,就实现了生成的嵌套。
实现生成器的嵌套,并非必定必需要使用yield from,而是使用yield from可让咱们避免让咱们本身处理各类料想不到的异常,而让咱们专一于业务代码的实现。
若是本身用yield去实现,那只会加大代码的编写难度,下降开发效率,下降代码的可读性。code
# 子生成器 def average_gen(): total = 0 count = 0 average = 0 while True: new_num = yield average count += 1 total += new_num average = total/count # 委托生成器 def proxy_gen(): while True: yield from average_gen() # 调用方 def main(): calc_average = proxy_gen() next(calc_average)# 预激下生成器 print(calc_average.send(10)) print(calc_average.send(20)) print(calc_average.send(30)) main()
结果以下:
10.0 15.0 20.0
委托生成器的做用:
在调用方与子生成器之间创建一个双向通道。
双向通道就是调用方能够经过send()
直接发送消息给子生成器,而子生成器yield的值,也是直接返回给调用方。
yield from帮咱们作了不少的异常处理,而这些若是咱们要本身去实现的话,一个是编写代码难度增长,写出来的代码可读性不好,极可能有遗漏,只要哪一个异常没考虑到,都有可能致使程序崩溃。
为了简化并更好地标识异步IO,从Python 3.5开始引入了新的语法async和await,可让coroutine的代码更简洁易读。
可将上面的案例代码改造以下:
import asyncio # @asyncio.coroutine async def test(i): print('test_1', i) # r = yield from asyncio.sleep(1) await asyncio.sleep(1) print('test_2', i) loop = asyncio.get_event_loop() tasks = [test(i) for i in range(1,3)] loop.run_until_complete(asyncio.wait(tasks)) loop.close()
执行结果
test_1 1 test_1 2 test_2 1 test_2 2
async
替换 @asyncio.coroutine
,加在def以前用于修饰await
替换yield from