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

return(yield from future)这一句,有两个动作第一个是把未完成future传递给事件循环,让事件循环继续运行;第二个等到任务真正完成的时候,事件循环到了才发送结果到 return的右边的临时变量,再返回。

阻塞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建立的联系?

上文已解释。

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值