py2.x协程
-
yield
:py2.x的协程都是通过yield生成器来实现的,可以说是模拟的协程(不能跨堆栈),yield可以暂停函数执行,send通知函数继续往下执行,并提供给yield值,yield和send这种交互就构成了协程的基础.2.x系列理解yield就理解协程,参考
http://blog.csdn.net/secretx/article/details/43969101
或者看书"编写高质量代码python代码的99个建议"其中有一节讲yield很不错 -
gevent
2系列协程的王牌产品
gevent 的两个关键的部件:hub和loop。loop是Gevent 的核心部件,也就是事件循环核心,默认是用Cython写的libev的包装。hub则是一个greenlet,主协程,其他子协程由他创建并且调度,所有子协程交出CPU使用权都给他,他再给非阻塞的可执行的其他子协程,里面跑着loop。
py3.4 asyncio
- Python 3.3引入yield from(PEP 380),简单点说就是可以在协程里写return,另一个协程里yield from接收这个return值
- Python3.4引入asyncio, asyncio是一个事件循环,类似libev,或者类比tornado的IOloop或者gevent的loop,hub,用来调度协程,同时使用@asyncio.coroutine来把函数装饰成协程,搭配上yield from实现基于协程的异步并发,此时协程还是靠yield模拟
py3.5协程
-
async/await
, 3.5引入的新东西,就简单看成asyncio/yield from
的升级版吧,在语言层面直接用async
await
提供对协程了支持,此后协程会与生成器yield分开界限 -
async def
定义一个协程func>>> async def coro(): ... return 'spam'
-
await
挂起当前协程用于非阻塞等待某个事件,比如IO;async for
用于异步迭代其他协程返回的结果import asyncio
async def httpget(domain): reader, writer = await asyncio.open_connection
(domain,80)#等待链接成功 writer.write(b'\r\n'.join([b'GET / HTTP/1.1', b'Host: %b' % domain.encode('latin-1'), b'Connection: close', b'', b''])) async for line in reader:#异步迭代 print('>>>', line) writer.close()
loop = asyncio.geteventloop() try: loop.run_until_complete
(httpget('example.com')) finally: loop.close() -
async with
asynchronous context managers,与with类似,仅仅用于管理协程的上下文环境import asyncio async def coro(name, lock): print('coro {}: waiting for lock'.format(name)) async with lock: print('coro {}: holding the lock'.format(name)) await asyncio.sleep(1) print('coro {}: releasing the lock'.format(name))
输出结果
loop = asyncio.get_event_loop
() lock = asyncio.Lock() coros = asyncio.gather(coro(1, lock), coro(2, lock))
try: loop.run_until_complete
(coros) finally: loop.close()coro 2: waiting for lock coro 2: holding the lock coro 1: waiting for lock coro 2: releasing the lock coro 1: holding the lock coro 1: releasing the lock