Python3 asyncio 例程

来源:互联网 发布:重生之女土匪知乎 编辑:程序博客网 时间:2024/06/06 01:39

asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持。asyncio的异步操作,需要在coroutine中通过yield from完成。

event loop 对象包含两个部分:event 和 loop。event 负责 I/O 事件通知而 loop 负责循环处理 I/O 通知并在就绪时调用回调。这里 event 的含义与 select 中的 event mask 类似。

协程可以处理IO密集型程序的效率问题,但是处理CPU密集型不是它的长处,如要充分发挥CPU利用率可以结合多进程+协程。


先分析一个例子:

import asyncio@asyncio.coroutinedef wget(host):    connect = asyncio.open_connection(host, 80)    reader, writer = yield from connect    header = 'GET / HTTP/1.0\r\nHost: %s\r\n\r\n' % host    writer.write(header.encode('utf-8'))    yield from writer.drain()    while True:        line = yield from reader.readline()        if line == b'\r\n':            break        print('%s header > %s' %(host, line.decode('utf-8').rstrip()))  #rstrip() 删除 string 字符串末尾的指定字符(默认为空格)    writer.close()loop = asyncio.get_event_loop()tasks = [wget(host) for host in ['www.baidu.com', 'www.google.com', 'www.sina.com', 'www.sohu.com', 'www.163.com']]loop.run_until_complete(asyncio.wait(tasks))loop.close()

@asyncio.coroutine把一个generator标记为coroutine类型,然后,我们就把这个coroutine扔到EventLoop中执行。

drain的官方解释:

drain() gives the opportunity for the loop to schedule the write operation and flush the buffer. It should especially be used when a possibly large amount of data is written to the transport, and the coroutine does not yield-from between calls to write().

在事件循环中刷新缓冲区,特别是在数据量很大的情况下,保证数据完整性.

yield from语法可以让我们方便地调用另一个generator,当connect 阻塞以后,不会等待,而是返回执行下一个消息循环,连接下一个链接

如果在header下方加一个打印print(header):

GET / HTTP/1.0Host: www.sohu.comGET / HTTP/1.0Host: www.163.comGET / HTTP/1.0Host: www.baidu.comwww.sohu.com header > HTTP/1.1 200 OKwww.sohu.com header > Content-Type: text/html;charset=UTF-8www.sohu.com header > Connection: closewww.sohu.com header > Server: nginxwww.sohu.com header > Date: Thu, 13 Jul 2017 07:48:39 GMTwww.sohu.com header > Cache-Control: max-age=60.........................
最后阻塞在google 网络链接错误后退出.

asynico/await

为了简化并更好地标识异步IO,从Python 3.5开始引入了新的语法async和await,可以让coroutine的代码更简洁易读。

async 是明确将函数声明为协程的关键字,即使没有await表达式,函数执行也会返回一个协程对象。

在协程函数内部,可以在某个表达式之前使用 await 关键字来暂停协程的执行,以等待某协程完成.
请注意,async和await是针对coroutine的新语法,要使用新的语法,只需要做两步简单的替换:

把@asyncio.coroutine替换为async;
把yield from替换为await。

代码变成:

import asyncioasync def wget(host):    connect = asyncio.open_connection(host, 80)    reader, writer = await connect    header = 'GET / HTTP/1.0\r\nHost: %s\r\n\r\n' % host    writer.write(header.encode('utf-8'))    await writer.drain()    while True:        line = await reader.readline()        if line == b'\r\n':            break        print('%s header > %s' %(host, line.decode('utf-8').rstrip()))    writer.close()loop = asyncio.get_event_loop()tasks = [wget(host) for host in ['www.sina.com', 'www.sohu.com', 'www.163.com']]loop.run_until_complete(asyncio.wait(tasks))loop.close()