python协程的前世今生,future、yield、loop、task,yield from各个关键字详细图解

异步实现的三种方式:

1、callback,callback注册

2、添加到队列

3、placeholder(站位), yield future

协程式的优点:

1、无cpu分时切换线程保存上下文问题(协程上下文怎么保存)

2、遇到io阻塞切换(怎么实现的)

3、无需共享数据的保护锁(为什么)

关键概念:

1、协程式都是由loop调用

2、生成器函数(参数)得到一个生成器对象gen, next(gen)等于gen.send(None),

3、yield(出生成器),gen.send(something)会回到生成器,传递给yield左边,send是生成器独有的


下面用典型的协程逻辑代码分析:

import asyncio
import random
async def smart_fib(n):
    index = 0
    a = 0
    b = 1
    while index < n:
        sleep_secs = random.uniform(0, 0.2)
        await asyncio.sleep(sleep_secs)
        print('Smart one think {} secs to get {}'.format(sleep_secs, b))
        a, b = b, a + b
        index += 1

async def stupid_fib(n):
    index = 0
    a = 0
    b = 1
    while index < n:
        sleep_secs = random.uniform(0, 0.4)
        await asyncio.sleep(sleep_secs)
        print('Stupid one think {} secs to get {}'.format(sleep_secs, b))
        a, b = b, a + b
        index += 1


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    tasks = [
        asyncio.ensure_future(smart_fib(10)),
        asyncio.ensure_future(stupid_fib(10)),
    ]
    loop.run_until_complete(asyncio.wait(tasks))
    print('All fib finished.')
    loop.close()

宏观上loop和协程的运行过程:


Task是future的子类,增加了对协程函数的调度;协程函数是放在ensure_future or create_task,然后loop.run_until_complete(task),多个任务需要asyncio.wait(tasks)或者asyncio.gather(*tasks)。

A = yield from B(await类似就不讲了),右边B是跟着的coroutine、阻塞IO或者future--send过去的,左边A处理结果 expression或者exception--yield出来,

由此可以看出:yield from约等于yield+异常处理+send


协程微观下运行过程:


关键代码:

@coroutine
def sleep(delay, result=None, *, loop=None):
    future = loop.create_future()
    h = future._loop.call_later(delay,
                                futures._set_result_unless_cancelled,
                                future, result)
    try:
        return (yield from future)  #这里是疑问的地方
    finally:
        h.cancel()

阻塞io通过future保存未来的结果,因为future具有没有完成loop可以循环调启future(可以多次send,可以多次yield返回)

class Future:    
    def __iter__(self):
        if not self.done():
            self._asyncio_future_blocking = True
            yield self  # This tells Task to wait for completion.
        assert self.done(), "yield from wasn't used with future"
        return self.result()  # May raise too.

延伸:gevent轮询检测IO阻塞和完成的时候,切换下一个任务;需要定时识别,运行效率没有原生协程高效。

问题: 阻塞IO里面,yield from future到底做了什么,看情况应该是还给loop了而不可能是阻塞这里了,怎样和loop建立的联系

猜你喜欢

转载自blog.csdn.net/sf131097/article/details/80377645
今日推荐