当前位置: 首页 > 工具软件 > asyncio > 使用案例 >

Python3 asyncio 例程

阎慈
2023-12-01

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.coroutine
def 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.0
Host: www.sohu.com


GET / HTTP/1.0
Host: www.163.com


GET / HTTP/1.0
Host: www.baidu.com


www.sohu.com header > HTTP/1.1 200 OK
www.sohu.com header > Content-Type: text/html;charset=UTF-8
www.sohu.com header > Connection: close
www.sohu.com header > Server: nginx
www.sohu.com header > Date: Thu, 13 Jul 2017 07:48:39 GMT
www.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 asyncio

async 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()


 类似资料: