zoukankan      html  css  js  c++  java
  • 异步IO(协程,消息循环队列)

    同步是CPU自己主动查看IO操作是否完成,异步是IO操作完成后发出信号通知CPU(CPU是被通知的)

    阻塞与非阻塞的区别在于发起IO操作之后,CPU是等待IO操作完成再进行下一步操作,还是不等待去做其他的事直到IO操作完

    成了再回来进行。

    消息模型:当遇到IO操作时,代码只负责发出IO请求,不等待IO结果,然后直接结束本轮消息处理,进入下一轮

    消息处理过程。当IO操作完成后,将收到一条“IO完成”的消息,处理该消息时就可以直接获取IO操作结果。

    子程序调用总是一个入口,一次返回,调用顺序是明确的,而协程的调用和子程序不同(有多个入口,多次返回)。

    #协程看上去也是子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行

    协程子程序切换不是线程切换(系统自动执行),而是有程序自身控制。

    #Python对协程的支持是通过generator实现的。

    #在generator中,我们不但可以通过for循环来迭代,还可以不断调用next()函数获取有yield语句返回的下一个值。

    #但是Python的yield不但可以返回一个值,还可以接收调用者发出的参数。

    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)  #调用c.send(None)启动生成器,程序跳转到consumer,运行至yield 处结束返回produce.

        n=0

        while n<5:

            n=n+1

            print('[PRODUCER]Producing %s...' %n)

            r=c.send(n) #通过c.send(n)切换到consumer执行

            print('[PRODUCER]cONSUMER RETURN: %s' %r)

        c.close()

    c=consumer()

    produce(c)

    '''

    1.首先调用c.send(None)启动生成器

    2.然后,一旦产生了东西,通过c.send(n)切换到consumer执行

    3.consumer通过yield拿到消息,处理,又通过yield把结果传回

    4.produce拿到consumer处理的结果,继续生产下一条消息

    5.produce决定不生产了,通过c.close()关闭consumer,整个过程结束。

    整个流程无锁,由一个线程执行,produce和consumer协作完成任务,所以称为“协程”而非线程的抢占式多任务。

     

    send()和yield相互为  发送和接收 参数  r=c.send(n),将参数n 传递给c函数,由c函数中的yield 及其后的变

    量 接收,c中的程序再次运行到yield时,yield将其后的变量作为返回值,也就是c.send(n)的值

    '''

    '''

    [PRODUCER]Producing 1...

    [CONSUMER]Consuming 1...

    [PRODUCER]cONSUMER RETURN: 200 OK

    [PRODUCER]Producing 2...

    [CONSUMER]Consuming 2...

    [PRODUCER]cONSUMER RETURN: 200 OK

    [PRODUCER]Producing 3...

    [CONSUMER]Consuming 3...

    [PRODUCER]cONSUMER RETURN: 200 OK

    [PRODUCER]Producing 4...

    [CONSUMER]Consuming 4...

    [PRODUCER]cONSUMER RETURN: 200 OK

    [PRODUCER]Producing 5...

    [CONSUMER]Consuming 5...

    [PRODUCER]cONSUMER RETURN: 200 OK

    '''

     

    #asyncio是Python3.4版本引入的标准库,直接内置了对异步IO的支持

    #asyncio的编程模型就是一个消息循环。我们从asyncio模块中直接获取一个Eventloop的引用,然后把需要执行的协程扔到Eventloop中执行,就实现了异步IO。

    #用asyncio实现Hello world 代码如下:

    '''

    import threading 

    import asyncio

    @asyncio.coroutine 

    def hello():

        print('Hello world! (%s)' %threading.currentThread())

        yield from asyncio.sleep(1)

        print('Hello again!(%s)' % threading.currentThread())

        

    loop=asyncio.get_event_loop()

    tasks=[hello(),hello()]

    loop.run_until_complete(asyncio.wait(tasks))

    loop.close()

    '''

    '''

    Hello world! (<_MainThread(MainThread, started 5524)>)

    Hello world! (<_MainThread(MainThread, started 5524)>)

    (暂停约1秒)

    Hello again!(<_MainThread(MainThread, started 5524)>)

    Hello again!(<_MainThread(MainThread, started 5524)>)

    '''

    # @asyncio.coroutine把一个generator标记为corroutine类型,然后,我们就把这个coroutine扔到Eventloop

    中执行。

    #hello()会首先打印出Hello world!,然后,yield from 语法可以让我们方便地调用另一个generator.由于

    asyncio.sleep()也是一个coroutine,所以线程不会等待

    #asyncio.sleep(),而是直接中断并执行下一个消息循环。当asyncio.sleep()返回时,线程就可以从yield from 

    拿到返回值(此处是None),然后接着执行下一行语句。

     

    #把asyncio.sleep(1)看成是一个耗时1秒的IO操作,在此期间,主线程并未等待,而是去执行Eventloop中其他可以执

    行的coroutine了,因此可以实现并发执行。

    多个coroutine可以封装成一组task然后并发执行。

     

    asyncio的编程模型就是一个消息循环。我们从asyncio模块中直接获取一个Eventloop的引用,然后把需要执行的协程扔

    到Eventloop中执,就实现了异步IO。

    为了简化并更好地标识异步IO,从Python3.5开始引入新的语法async和await,可以让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!")

    '''

     

    #剩下的代码保持不变

     

    #aiohttp

    #asyncio可以实现单线程并发IO操作。如果仅用在客户端,发挥的威力不大。如果把asyncio用在服务器端,例如web服务器,由于http连接就是IO操作,因此可以用

    #单线程+coroutine实现多用户的高并发支持。

     

    #asyncio实现了TCP UDP SSL等协议,aiohttp则是基于asyncio实现的http框架。

     

    #编写一个http服务器    ,分别处理一下URL:

    '''

    * /  -首页返回b'<h1>Index</h1>';

    * /hello/{name}  -根据URL参数返回文本 hello,%s!.

    '''

     

    import asyncio 

    from aiohttp import web

    async def index(request):

        await asyncio.sleep(0.5)

        return web.Response(body=b'<h1>Index</h1>',content_type='text/html')

     

    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'),content_type='text/html')

     

    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 

    loop=asyncio.get_event_loop()

    loop.run_until_complete(init(loop))

    loop.run_forever()

     

    #aiohttp的初始化函数init()也是一个coroutine,loop.create_server()则利用asyncio创建TCP服务

  • 相关阅读:
    vue $emit的使用
    flask config 环境变量配置
    get请求
    下载及安装
    测试用例写作
    系统测试
    测试方法
    软件质量
    测试基础
    子网掩码
  • 原文地址:https://www.cnblogs.com/Ting-light/p/9547350.html
Copyright © 2011-2022 走看看