再次理解Python中async/await语法作用机理

  • 前言

    async/await是Python3.5提出的用于规范异步编程的语法糖,理解起来比较困难,前面研究了几天还是迷迷糊糊,今天在其基础上,再细读一遍。

  • 发展历史

    Python3.3–>yield from (关键字)

    Python3.4–>asyncio (标准库)

    以上两者结合,产生了Python3.5–>async/await (关键字)

    so,anyone want to truly understand how async/await work should know yield and asyncio first, and also coroutine.

    1. about the keyword yield ,see the artical《理解Python关键字yield与generator》
    2. asyncio is an event loop framework which allowed for asynchronous programing.《理解Python异步中的事件循环(asyncio管理事件循环)》
    3. coroutine,according to Wikipedia, “Coroutines are computer program components that generalize subroutines for nonpreemptive multitasking, by allowing multiple entry points for suspending and resuming execution at certain locations”.In other words, coroutines are functions whose execution you can pause.which sounds like generators,but acctually not.
  • The way it(async/await) was in Python 3.4

    在asyncio之前,Python采用concurrent programming的方式来实现asynchronous programming。

    import asyncio
    
    # Borrowed from http://curio.readthedocs.org/en/latest/tutorial.html.
    @asyncio.coroutine
    def countdown(number, n):
        while n > 0:
            print('T-minus', n, '({})'.format(number))
            yield from asyncio.sleep(1)
            n -= 1
    
    loop = asyncio.get_event_loop()
    tasks = [
        asyncio.ensure_future(countdown("A", 2)),
        asyncio.ensure_future(countdown("B", 3))]
    loop.run_until_complete(asyncio.wait(tasks))
    loop.close()
    

    在Python3.4用asyncio.coroutine装饰器来标识一个函数为coroutine。也就是意味着使用asyncio及其event loop。

    因为generator和coroutine之间有些定义上的混淆,故此使用这个装饰器来区别coroutine。

    With this concrete definition of a coroutine(Which matched an API that generators provided), you then used yield from on any asyncio.Future object to pass it down to the event loop,pausing execution of the coroutine while you waited for something to happen.

    Once the future object reached the event loop it was monitored there until the future object was done doing whatever it needed to do.

    Once the future was done doing its thing, the event loop noticed and the coroutine that was paused waiting for the future’s result started again with its result sent back into the coroutine into the coroutine using its send() method.

    async def function(): # coroutine
        ...
        yield from asyncio.future # future
    

    Take our example above.The event loop starts each of the countdown() coroutine calls, executing until it hits yield from and the asyncio.sleep() function in one of them. That returns an asyncio.Future object which gets passed down to the event loop and pauses execution of the coroutine.There the event loop watches the future object until the one second is over(as well as checking on other stuff it’s watching, like the other coroutine). Once the one second is up, the event loop takes the paused countdown() coroutine that gave the event loop the future object,sends the result of the future object back into the coroutine that gave it the future object in the first place, and the coroutine starts running again. This keeps going until all of the countdown() coroutines are finished runing and the event loop has nothing to watch.

  • Going from yield from to await in Python 3.5

    In Python 3.4, a function that was flagged as a coroutine for the purposes of asynchronous programming looked like:

    @asyncio.coroutine
    def py34_coro():
        yield from stuff()
    

    In Python 3.5,the types.coroutine decorator has been added to also flag a generator as a coroutine like asyncio.coroutine does. You can alse use async def to syntactically define a function as being a coroutine, although it cannot contain any form of yield expression; only return and await are allowed for returning a value from the coroutine:

    async def py35_coro():
        await stuff
    

    await operates is only valid within an async def.While await operates much like yield from ,the objects that are acceotable to an await expression are different.

    when you call await on an object, it technically needs to be an awaitable object: an object that defines an __await__()method which returns an iterator.

  • Think of async/await as an API for asynchronous programming

    According talk from David Beazley, async/await is really an API for asynchronous programming.

    Which means that people shouldn’t think what async/await as synonymous with asyncio, but instead think that asyncio is a framework that can utilize the async/await API for asynchronous programming.

    asyncio uses future objects as the API for talking to its event loop while curio uses tuples.

  • References

  1. How the heck does async/await work in Python 3.5? 【here is all you should know about async/await】

猜你喜欢

转载自blog.csdn.net/The_Time_Runner/article/details/105801522