3.4. 异步IO

3.4.1. 协程

子程序调用总是一个入口,一次返回,调用顺序是明确的。而协程的调用和子程序不同。

协程看上去也是子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。

优势

  • 一般不需要枷锁

  • 协程极高的执行效率

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

3.4.2. async/await

import asyncio
async def main():
    print('Hello ...')
    await asyncio.sleep(1)
    print('... World!')
asyncio.run(main())

3.4.3. 同步和异步对比

import asyncio
import time 

async def count1():
    print("One")
    await asyncio.sleep(1)
    print("Two")

async def work1():
    await asyncio.gather(count1(), count1(), count1())

def v1():
    import time
    s = time.perf_counter()
    asyncio.run(work1())
    elapsed = time.perf_counter() - s
    print(f"{__file__} executed in {elapsed:0.2f} seconds.")

def v2():
    s = time.perf_counter()
    work2()
    elapsed = time.perf_counter() - s
    print(f"{__file__} executed in {elapsed:0.2f} seconds.")

def count2():
    print("One")
    time.sleep(1)
    print("Two")

def work2():
    for _ in range(3):
        count2()

if __name__ == "__main__":
    v1()
    v2()

3.4.4. aiohttp

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

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 http://127.0.0.1:8000...')
    return srv

loop = asyncio.get_event_loop()
loop.run_until_complete(init(loop))
loop.run_forever()