• 异步IO:async/await


      async/await

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

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

      请注意,asyncawait是针对coroutine的新语法,要使用新的语法,只需要做两步简单的替换:

    1. @asyncio.coroutine替换为async
    2. 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!")
    

      剩下的代码保持不变。

      小结:

      Python从3.5版本开始为asyncio提供了asyncawait的新语法;

      注意新语法只能用在Python 3.5以及后续版本,如果使用3.4版本,则仍需使用上一节的方案。

       练习

      将上一节的异步获取sina、sohu和163的网站首页源码用新语法重写并运行。

      async_hello2.py

    import asyncio
    import threading
    import time
    
    async def hello():
        print('Hello world! %s' % threading.currentThread() )
        await asyncio.sleep(1)   
        print('Hello again! %s' % threading.currentThread())
    
    # 获取Eventloop事件循环
    loop = asyncio.get_event_loop()
    # 执行协程,协程函数不能直接执行,需要放入事件循环才能执行
    tasks = [hello(),hello()]
    loop.run_until_complete(asyncio.wait(tasks))
    # 关闭事件循环
    loop.close()
    # 封装两个task任务 end
    

      async_wget2.py

    import asyncio
    async def wget(host):
        print('wget %s...' % host)
        # 创建TCP客户端并连接服务器,或者说创建一个TCP连接对象
        # open_connection接收两个参数:主机名和端口号
        # connect是协程,这步仅创建协程对象,立即返回,不阻塞
        connect = asyncio.open_connection(host,80)
        # 运行协程连接服务器,这步是阻塞操作,释放CPU
        # 连接创建成功后,asyncio.open_connection方法返回的就是读写对象
        # 读写对象分别为 StreamReader和StreamWriter实例
        # 它们也是协程对象,底层调用Socker模块的send和recv方法实现读写
        reader,writer = await connect
        # heade是发送给服务器的消息,意为获取页面的header信息
        # 它的格式是固定的
        header = 'GET / HTTP/1.0
    Host: %s
    
    ' %host
        # 给服务器发消息,注意消息是二进制的,本次使用utf-8编码
        writer.write(header.encode('utf-8'))
        # writer.drain()是一个与底层IO输入缓冲区交互流量控制方法,需要配合writer.write使用
        # 当缓冲区达到上限时,drain()阻塞,待缓冲区回落到下限时,写操作恢复
        # 当不需要等待时,drain()会立即返回,假如上面的消息内容较少,不会阻塞
        # 这就是一个控制消息数据量的控制阀
        await writer.drain()
        # 给服务器发送消息后,就等着读取服务器返回来的消息
        while True:
            # 读取数据是阻塞操作,释放CPU
            # reader相当于一个水盆,服务器发来的数据是水流
            # readline表示读取一行,以
    作为换行符
            # 如果在出现
    之前,数据流出现EOF(End of File文件结束符)也会返回
            # 相当于出现
    或EOF时,拧上水龙头,line就是这盆水
            line = await reader.readline()
            # 数据接收完毕,会返回空字符串
    ,退出while循环,结束数据接收
            if line == b'
    ':
                break
            # 接收数据是二进制,转换为UTF-8格式并打印
            # rstrip()方法删掉字符串结尾就是右边的空白字符,也就是
    
            print('%s header > %s' % (host,line.decode('utf-8').rstrip()))
        # 关闭数据流,可以省略
        writer.close()
        await writer.wait_closed()
    
    hosts = ['192.168.1.100']
    hosts = ['www.sina.com.cn','www.sohu.com','www.163.com']
    # 创建task任务
    tasks = [wget(host) for host in hosts ]
    # 创建事件循环
    loop = asyncio.get_event_loop()
    # 运行事件循环
    loop.run_until_complete(asyncio.wait(tasks))
    

      

      

     

      

  • 相关阅读:
    JS开发框架DevExtreme v20.1.7上线
    Web开发:看如何定义Kendo UI Grid Width
    如何创建自定义DevExpress报表控件,看完你就懂了
    高性能HTML5/JavaScript开发框架DevExtreme全新发布v20.1.7|附下载
    WPF界面开发:如何将不同集合中的项目显示为同一父节点子项
    界面开发包DevExpress v20.1.7上线!即刻体验
    WPF界面开发2020:Scheduler等控件功能升级
    Winform界面开发看过来!一招教你使用属性网格自定义编辑器
    将从数据库查询出来的带有父子结构的list转换成treeList结构
    将JDBC ResultSet结果集转成List
  • 原文地址:https://www.cnblogs.com/minseo/p/15484885.html
Copyright © 2020-2023  润新知