async/await协程语法

2019-07-12  本文已影响0人  蕴重Liu

协程函数(异步函数)
使用async关键词将其变成协程方法

执行协程

协程函数执行结束时会抛出一个StopIteration 异常,标志着协程函数执行结束,返回值在value中

def running():
    async def test1():
        print('1')
        print('2')
    async def test2():
        print('3')
        print('4')
    a = test1()
    b = test2()

    try:
        a.send(None)
    except StopIteration as e:
        print(e.value)
    try:
        b.send(None)
    except StopIteration as e:
        print(e.value)

if __name__ == '__main__':
    running()
输出:
1
2
None
3
4
None

交叉执行协程函数

def running1():
    import asyncio
    async def test1():
        print('1')
        await asyncio.sleep(0.01)
        -- 一旦协程函数执行过程中切换到其他函数,那么这个函数不再继续运行
        print('2')

    async def test2():
        print('3')
        print('4')

    a = test1()
    b = test2()

    try:
        a.send(None)           --send方法效率不是很高效
    except StopIteration as e:
        print(e.value)
    try:
        b.send(None)
    except StopIteration as e:
        print(e.value)

if __name__ == '__main__':
    running1()

输出:
1
3
4
None

程序先执行test1协程函数,在执行到await时,test1函数停止了执行(阻塞);接着开始执行test2协程函数,直到test2执行完毕.

await与阻塞
   使用async可以定义协程对象,使用await可以针对耗时的操作进行挂起,就像生成器里的yield一样,函数让出控制权。协程遇到await,事件循环将会挂起该协程,执行别的协程,直到其他的协程也挂起或者执行完毕,再进行下一个协程的执行,协程的目的也是让一些耗时的操作异步化
   注意点:await后面跟的必须是一个Awaitable对象,或者实现了相应协议的对象,查看Awaitable抽象类的代码,表明了只要一个类实现了await方法,那么通过它构造出来的实例就是一个Awaitable,并且Coroutine类也继承了Awaitable。

自动循环执行协程函数

事件循环方法:asyncio.get_event_loop方法

def running1():
    import asyncio
    async def test1():
        print('1')
        await test2()
        print('2')

    async def test2():
        print('3')
        print('4')

    loop = asyncio.get_event_loop()
    loop.run_until_complete(test1())

if __name__ == '__main__':
    running1()

输出:
1
3
4
2

说明:asyncio.get_event_loop方法可以创建一个事件循环,然后使用run_until_complete将协程注册到事件循环,并启动事件循环

task对象保存了协程运行的状态,并且可以获取协程函数运行的返回值

def running1():
    import asyncio
    async def test1():
        print('1')
        await test2()
        print('2')
        return 'return'

    async def test2():
        print('3')
        print('4')

    loop = asyncio.get_event_loop()
    task = asyncio.ensure_future(test1())
    loop.run_until_complete(task)
    print(task.result())

if __name__ == '__main__':
    running1()

输出:
1
3
4
2
return
def running1():
    import asyncio
    async def test1():
        print('1')
        await test2()
        print('2')
        return 'return'

    async def test2():
        print('3')
        print('4')

    def callback(future):
        print('Callback:', future.result())       --通过future对象的result方法可以获取协程函数的返回值

    loop = asyncio.get_event_loop()
    task = asyncio.ensure_future(test1())      --# 创建task,test1()是一个协程对象
    task.add_done_callback(callback)   --绑定回调函数
    loop.run_until_complete(task)

if __name__ == '__main__':
    running1()

输出:
1
3
4
2
Callback: return

======================回调函数接收多个参数
def running2():
    import asyncio
    import functools
    async def test1():
        print('1')
        await test2()
        print('2')
        return 'oooo'

    async def test2():
        print('3')
        print('4')

    def callback(param1, param2, future):
        print(param1, param2)
        print('Callback:', future.result())        --future是创建的task对象

    loop = asyncio.get_event_loop()
    task = asyncio.ensure_future(test1())
    task.add_done_callback(functools.partial(callback, 'p1', 'p2'))
    loop.run_until_complete(task)

if __name__ == '__main__':
    running2()

输出:
1
3
4
2
p1 p2
Callback: oooo

future对象
   状态:Pending Running Done Cancelled
   创建future的时候,task为pending,事件循环调用执行的时候当然就是running,调用完毕自然就是done,如果需要停止事件循环,就需要先把task取消,可以使用asyncio.Task获取事件循环的task

协程停止

停止协程前,先取消task,然后再停止loop事件循环

def running3():
    import asyncio
    async def test1():
        print('1')
        await asyncio.sleep(3)
        print('2')
        return 'stop'

    tasks = [
        asyncio.ensure_future(test1()),
        asyncio.ensure_future(test1()),
        asyncio.ensure_future(test1())
    ]

    loop = asyncio.get_event_loop()
    try:
        loop.run_until_complete(asyncio.wait(tasks))
    except KeyboardInterrupt as e:
        for task in asyncio.Task.all_tasks():
            task.cancel()
        loop.stop()
        loop.run_forever()
    finally:
        loop.close()

if __name__ == '__main__':
    running3()

输出:
1
1
1
2
2
2

并发与并行

asyncio实现并发

asyncio想要实现并发,就需要多个协程来完成任务,每当有任务阻塞的时候就await,然后其他协程继续工作,这需要创建多个协程的列表,然后将这些协程注册到事件循环中。

多协程:多个协程函数,,或 一个协程函数的多个协程对象

def running4():
    import asyncio
    async def test1():
        print('1')
        await asyncio.sleep(2)
        print('2')
        return 'gg'

    a = test1()
    b = test1()
    c = test1()

    -- 通过asyncio.ensure_future方法创建了三个task
    tasks = [
        asyncio.ensure_future(a),
        asyncio.ensure_future(b),
        asyncio.ensure_future(c)
    ]
    loop = asyncio.get_event_loop()

    --使用run_until_complete将task列表添加到事件循环中
    loop.run_until_complete(asyncio.wait(tasks))
    for task in tasks:
        print('task result is ', task.result())

if __name__ == '__main__':
    running4()

输出:
1
1
1
2
2
2
task result is  gg
task result is  gg
task result is  gg

协程爬虫

https://thief.one/2018/06/21/1/

上一篇下一篇

猜你喜欢

热点阅读