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

      

  • 相关阅读:
    [Qt] 文本文件读写, 摘自官方文档
    [Windows] Socket Server Failed to bind, error 10048
    lodctr /R 失败的情况
    ModuleNotFoundError: No module named 'sklearn.cross_validation'
    [Qt] 通过socket将另一个程序的某个窗口调到最前端
    SortedDictionary<TKey, TValue> 类 表示根据键进行排序的键/值对的集合。
    finally不管有没有错都会运行 finally 块用于清除 try 块中分配的任何资源,以及运行任何即使在发生异常时也必须执行的代码
    HttpWebRequest使用证书请求
    string StartsWith 方法 Https
    设置https验证方式
  • 原文地址:https://www.cnblogs.com/weihuchao/p/7010547.html
Copyright © 2011-2022 走看看