协程

微线程,纤程 -- Coroutine

子程序(函数) -- 所有语言中都是层级调用,子程序调用是一通过栈实现的,一个线程就是执行一个子程序。

子程序调用是明确的,一个入口,一次返回。

协程看上去像子程序,但在执行过程中可中断。有点像执行多线程,但是它是一个线程执行。

协程比多线程的优势:极高的执行效率,没有线程切换的开销;没有线程的锁机制。

使用协程利用多CPU的方式:多进程+协程


python对协程的支持通过generator实现。

通过for迭代,不断调用next()函数获取由yield返回的下一个值。

python的yield不但可以返回一个值,还可以接收调用者发出的参数。

生产者消费者通过yield的实例:

def consumer():
    r=''
    while True:
        n = yield r
        if not n:
            return
        print('[CONSUMER] Consuming %s...' % n)
        r = '200 OK'
        
def produce(c):
    c.send(None)
    n = 0
    while n < 5:
        n = n+1
        print('[PRODUCER] Producing %s...' % n)
        r = c.send(n)
        print('[PRODUCER] Consumer return: %s' % r)
    c.close()
    
c = consumer()
produce(c)


asyncio

asyncio的编程模型就是一个消息循环。

实现异步IO -- 从asyncio模块中获取一个eventloop的引用,然后把需要执行的协程扔到eventloop中执行。

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()
# 执行conroutine
loop.run_until_complete(hello())
loop.close()


async/await

async和await是针对coroutine的新语法,只需要做两部简单的替换。

  1. 把@asyncio.coroutine替换为async

  2. 把yield from 替换为await

async def hello():
    print("hello world!")
    r = await asyncio.sleep(1)
    print("hello again!")


aiohttp

asyncio实现了TCP、UDP、SSL协议,aiohttp基于asyncio实现的http框架。

一个aiohttp实现的http服务器。分别处理以下URL:

/ -- 返回b'<h1>Index</h1>'

/hello/{name} -- 根据URL参数返回文本hello,%s!

import asyncio

from aiohttp import web

async def index(request):
    await asyncio.sleep(0.5)
    return web.Response(body=b'<h1>Index</h1>')
    
async def hello(request):
    await asyncio.sleep(0.5)
    text='<h1>hello, %s!</h1>' % request.match_info['name']
    return web.Response(body=text.encode('utf-8'))
    
async def init(loop):
    app = web.Application(loop=loop)
    app.router.add_route('GET', '/', index)
    app.router.add_route('GET', '/hello/{name}', hello)
    srv = await loop.create_server(app.make_handler(), '127.0.0.1', 8000)
    print('Server started at 
    return srv
    
    
loop = asyncio.get_event_loop()
loop.run_until_complete(init(loop))
loop.run_forever()