异步 IO(二)

321 阅读2分钟

asyncio

asyncio 是 Python3 引入的标准库,直接内置了对异步 IO 的支持,asyncio 的编程模型是一个消息循环,我们从 asyncio 中直接获取一个 EventLoop 的引用,然后把需要执行的协程放到 EventLoop 中执行,就实现了异步 IO。

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!
  • @asyncio.coroutine 把一个 generator 标记为 coroutine 类型,然后把 coroutine 放到 EventLoop 中执行。
  • hello() 会首先打印出 Hello world!,然后 yield from 语法可以让我们方便调用另一个 generator,由于 asyncio.sleep() 也是一个 coroutine ,所以线程不会等待 asyncio.sleep(),而是直接中断并执行下一个消息循环。当 asyncio.sleep() 返回时,线程就可以从 yield from 拿到返回值(此处是 None ),然后接着执行下一行语句。
  • 把 asyncio.sleep(1) 看成是一个耗时一秒的 IO 操作,在此期间主线程并为等待,而是去执行 EventLoop 中其他可以执行的 coroutine 了,因此可以实现并发执行。

用 Task 封装两个 coroutine。

import threading
import asyncio

@asyncio.coroutine
def hello():
    print('Hello world! (%s)' % threading.currentThread())
    yield from asyncio.sleep(1)
    print('Hello again! (%s)' % threading.currentThread())

loop = asyncio.new_event_loop()
tasks = [hello(), hello()]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

运行结果:

Hello world! (<_MainThread(MainThread, started 140736185906112)>)
Hello world! (<_MainThread(MainThread, started 140736185906112)>)
(暂停约一秒)
Hello again! (<_MainThread(MainThread, started 140736185906112)>)
Hello again! (<_MainThread(MainThread, started 140736185906112)>)
  • 由运行结果可以看出两个 coroutine 是由同一个线程并发执行。如果把 asyncio.sleep() 换成真正的 IO 操作,则多个 coroutine 就可以由一个线程并发执行。

async/await

用 asyncio 提供的 @asyncio.coroutine 可以把一个 generator 标记为 coroutine 类型,然后在 coroutine 内部用 yield from 调用另一个 coroutine 实现异步操作。

为了简化操作,增强可读性,Python3.5 引入了 async 和 await 两个关键字,要使用这两个关键字只需要做两步简单的替换:

* 把 @asyncio.coroutine 替换成 async
* 把 yield from 替换成 await
	
# 上一节的代码
@asyncio.coroutine
def hello():
    print("Hello world!")
    r = yield from asyncio.sleep(1)
    print("Hello again!")
# 新语法重写
async def hello():
    print("Hello world!")
    r = await asyncio.sleep(1)
    print("Hello again!")

aiohttp

asyncio 可以实现单线程并发 IO 操作。如果仅用在客户端,发挥的威力不大。如果把 asyncio 用在服务器端,例如 Web 服务器,由于 HTTP 连接就是 IO 操作,因此可以用单线程+ coroutine 实现多用户的高并发支持。

asyncio 实现了 TCP、UDP、SSL 等协议,aiohttp 则是基于 asyncio 实现的 HTTP 框架。

本文参考: 廖雪峰: www.liaoxuefeng.com/wiki/101695…

每日格言:过去属于死神,未来属于你自己。

请作者坐公交 支付宝

支付宝

微信

微信