Python3 asyncio 例程

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利用率可以结合多进程+协程。

 

先分析一个例子:

 

[python] view plain copy
 
  1. import asyncio  
  2.  
  3. @asyncio.coroutine  
  4. def wget(host):  
  5.     connect = asyncio.open_connection(host, 80)  
  6.     reader, writer = yield from connect  
  7.     header = 'GET / HTTP/1.0\r\nHost: %s\r\n\r\n' % host  
  8.     writer.write(header.encode('utf-8'))  
  9.     yield from writer.drain()  
  10.     while True:  
  11.         line = yield from reader.readline()  
  12.         if line == b'\r\n':  
  13.             break  
  14.         print('%s header > %s' %(host, line.decode('utf-8').rstrip()))  #<span style="color: rgb(51, 51, 51); font-family: "Microsoft Yahei", "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 13px;">rstrip() 删除 string 字符串末尾的指定字符(默认为空格)</span>  
  15.     writer.close()  
  16.   
  17. loop = asyncio.get_event_loop()  
  18. tasks = [wget(host) for host in ['www.baidu.com', 'www.google.com', 'www.sina.com', 'www.sohu.com', 'www.163.com']]  
  19. loop.run_until_complete(asyncio.wait(tasks))  
  20. 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):

 

[python] view plain copy
 
  1. GET / HTTP/1.0  
  2. Host: www.sohu.com  
  3.   
  4.   
  5. GET / HTTP/1.0  
  6. Host: www.163.com  
  7.   
  8.   
  9. GET / HTTP/1.0  
  10. Host: www.baidu.com  
  11.   
  12.   
  13. www.sohu.com header > HTTP/1.1 200 OK  
  14. www.sohu.com header > Content-Type: text/html;charset=UTF-8  
  15. www.sohu.com header > Connection: close  
  16. www.sohu.com header > Server: nginx  
  17. www.sohu.com header > Date: Thu, 13 Jul 2017 07:48:39 GMT  
  18. www.sohu.com header > Cache-Control: max-age=60  
  19. .........................  

最后阻塞在google 网络链接错误后退出.

 

asynico/await

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

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

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

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

代码变成:

 

[python] view plain copy
 
    1. import asyncio  
    2.   
    3. async def wget(host):  
    4.     connect = asyncio.open_connection(host, 80)  
    5.     reader, writer = await connect  
    6.     header = 'GET / HTTP/1.0\r\nHost: %s\r\n\r\n' % host  
    7.     writer.write(header.encode('utf-8'))  
    8.     await writer.drain()  
    9.     while True:  
    10.         line = await reader.readline()  
    11.         if line == b'\r\n':  
    12.             break  
    13.         print('%s header > %s' %(host, line.decode('utf-8').rstrip()))  
    14.     writer.close()  
    15.   
    16. loop = asyncio.get_event_loop()  
    17. tasks = [wget(host) for host in ['www.sina.com', 'www.sohu.com', 'www.163.com']]  
    18. loop.run_until_complete(asyncio.wait(tasks))  
    19. loop.close()  
posted @ 2017-07-26 14:02  天涯海角路  阅读(196)  评论(0)    收藏  举报