zoukankan      html  css  js  c++  java
  • 第十七章-异步IO

    异步IO的出现源自于CPU速度与IO速度完全不匹配

    一般的可以采用多线程或者多进程的方式来解决IO等待的问题

    同样异步IO也可以解决同步IO所带来的问题

    常见的异步IO的实现方式是使用一个消息循环, 主线程不断的读取这个消息循环以便确定IO操作是否完成

    1 协程

      协程(微线程, 纤程)

      一般子程序调用是一个入口一个出口, 调用的顺序也是明确的

      但是协程不同, 执行过程中子程序内部中断, 就会转而执行别的子程序, 等待合适的时间返回 , 这样的行为类似于进程的切换 

      正因为协程又类似于线程执行的特性, 但是子程序切换几乎没有切换开销, 因此性能很好

      而且协程还可以避免临界资源操作的问题

      协程是一个线程执行

      构造协程一般是使用生成器, 利用send()发送相互传递数据

      常见的生产者消费者的范例

    def consumer():
        r = ''
        while True:
            n = yield r
            if not n:
                return
            print('[CONSUMER] Consuming %s...' % n)
            r = '200 OK'
    
    def produce(c):
        c.send(None)
        n = 0
        while n < 5:
            n = n + 1
            print('[PRODUCER] Producing %s...' % n)
            r = c.send(n)
            print('[PRODUCER] Consumer return: %s' % r)
        c.close()
    
    c = consumer()
    produce(c)
    

    2 asyncio

      基本使用为

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

      使用装饰器asyncio.coroutine装饰一个执行函数, 这样便可以生成一个异步执行IO的函数

      使用asyncio.get_event_loop()创建一个循环

      通过这个循环的对象执行run_until_complete()来执行异步IO

        其中run_until_complete()可以传入一个函数执行

        如果需要多个函数的话, 就需要将这些函数执行方法一个list中, 并使用asyncid.wait(list)

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

      最后调用close()结束异步IO

      其中函数的写法是 需要使用 yield from来实现异步IO

      获取网页的函数编写如下

    @asyncio.coroutine
    def wget(host):
        print('wget %s...' % host)
        connect = asyncio.open_connection(host, 80)
        reader, writer = yield from connect
        header = 'GET / HTTP/1.0
    Host: %s
    
    ' % host
        writer.write(header.encode('utf-8'))
        yield from writer.drain()
        while True:
            line = yield from reader.readline()
            if line == b'
    ':
                break
            print('%s header > %s' % (host, line.decode('utf-8').rstrip()))
        writer.close()
    

    3 async和await

      使用asyncio.coroutine可以吧一个生成器标记为coroutine类型

      然后在内部使用yield from调用另一个coroutine实现异步操作

      为了进一步简化操作, 出现了async和await, 这是在python3.5开始支持的语法

      简化如下

        1) 装饰器asyncio.corontine替换为async

        2) yield from替换为await

      因此上述代码可以简化为

    async def hello():
        print("Hello world!")
        r = await asyncio.sleep(1)
        print("Hello again!")
    
    async def wget(host):
        print('wget %s...' % host)
        connect = asyncio.open_connection(host, 80)
        reader, writer = await connect
        header = 'GET / HTTP/1.0
    Host: %s
    
    ' % host
        writer.write(header.encode('utf-8'))
        await writer.drain()
        while True:
            line = await reader.readline()
            if line == b'
    ':
                break
            print('%s header > %s' % (host, line.decode('utf-8').rstrip()))
        writer.close()
    

    4 aiohttp

      asyncio实现了单线程并发io操作, 如果只是应用于客户端, 那么作用还不是那么明显

      针对于服务器, asyncio可能发挥更好的效果, 基于http协议实现的asyncio就是aiohttp

      安装

    pip install aiohttp
    

      1) 导入包

    import asyncio
    from aiohttp import web
    

      2) 实现mian代码

    if __name__ == '__main__':
        loop = asyncio.get_event_loop()
        loop.run_until_complete(init(loop))
        loop.run_forever()
    

      3) 编写初始化函数

      将循环loop作为参数传入, 用于创建webapp

      添加路由, 并指定处理函数

      最后创建服务器, 利用create_server()创建TCP服务

    async def init(loop):
        app = web.Application(loop=loop)
        app.router.add_route('GET', '/', index)
        app.router.add_route('GET', '/hello/{name}', hello)
        srv = await loop.create_server(app.make_handler(), '127.0.0.1', 8000)
        print('Server started at http://127.0.0.1:8000...')
        return srv
    

      4) 编写两个路由的处理函数

    async def index(request):
        await asyncio.sleep(0.5)
        return web.Response(body=b'<h1>Index</h1>')
    
    async def hello(request):
        await asyncio.sleep(0.5)
        text = '<h1>hello, %s!</h1>' % request.match_info['name']
        return web.Response(body=text.encode('utf-8'))
    

      

  • 相关阅读:
    Linux内核RPC请求过程
    二分图
    Java实现 蓝桥杯 算法提高 合并石子
    Java实现 蓝桥杯 算法提高 合并石子
    Java实现 蓝桥杯 算法提高 摩尔斯电码
    Java实现 蓝桥杯 算法提高 摩尔斯电码
    Java实现 蓝桥杯 算法提高 文本加密
    Java实现 蓝桥杯 算法提高 文本加密
    Java蓝桥杯 算法提高 九宫格
    Java蓝桥杯 算法提高 九宫格
  • 原文地址:https://www.cnblogs.com/weihuchao/p/7010547.html
Copyright © 2011-2022 走看看