美文网首页
「Python异步编程-3」协程、生成器、yield 的联系

「Python异步编程-3」协程、生成器、yield 的联系

作者: 言淦 | 来源:发表于2018-09-25 09:48 被阅读0次

异步编程的基础在于理解协程,而协程的基础在于理解生成器,而生成器的基础在于理解yield关键字,下面就来说说这几个概念。

什么是yield关键字?
相当于return关键字,在每次next(),或者for遍历的时候,都会yield这里将新的值返回回去,并在这里阻塞,等待下一次的调用

什么是生成器?
每次触发只会返回一个值,用next(generator) 和generator.send() 触发,比如下面这个例子。

from collections.abc import Generator

def target(N):
    count = 0
    while count < N:
        yield count
        count += 1

tar = target(5)
print(isinstance(tar, Generator))  # True
print(next(tar))   # 0, 因为一开始count=0, 执行到yield count就把count返回,所以会打印 0
print(tar.send(None))  # 1, 执行完该语句后,会跳转到yield count;并继续执行count+=1, 所以count就变成1;再执行yield count, 将1返回。

生成器的注意事项?

  • 注意生成器的实例个数
  • 注意send()方法传递的参数
    • 当参数为None时, 与next(generator)等价
    • 当参数为数字时,会通过yield关键字传递到生成器

talk is cheap,show me the code!

# 第一个注意事项,生成器的实例个数(与之前的代码进行比较)
from collections.abc import Generator

def target(N):
    count = 0
    while count < N:
        yield count
        count += 1

print(isinstance(target(5), Generator))  # True
print(next(target(5)))  # 0 
print(target(5).send(None)) # 0,这里返回0是相当于创建一个新的生成器实例,所以第一个值返回的肯定是0

# 第二个注意事项,send方法传递的参数
# 1.jump = yield index 应该拆分为两个语句,分别是 jump = yield 和 yield(return) index;
# 2.jump = yield接收通过send()发送的信息,并赋值给jump;yield index 是将index return给外部程序。

def jumping_range(N):
    index = 0
    while index < N:
        jump = yield index
        if jump is None:
            jump = 1
        index += jump

if __name__ == '__main__':
    itr = jumping_range(5)
    print(itr.send(None)) # 1
    print(next(itr))  # 2
    print(itr.send(2))  # 3, 这条语句不能放到位置1, 具体可以自己尝试

想必到这里大家应该对生成器和yield有个了解,那什么是协程呢?

协程:
网上常见说法是轻量线程,它的关系类似与线程与进程的关系,但是它不用考虑线程安全。
我的理解是协程是程序之间协作配合,或者说是不同函数之间的配合,因为它的级别只是函数,所以它在单个线程内,也就不同考虑线程安全。而且如果我们把每个函数抽象为一个任务,其实协程实现了单线程多任务,这也是它的一个亮点之一,提升了效率。

这段话有两个比较难理解的,一是函数怎么配合?二是效率怎么提升?

# 在这段程序中,await asyncio.sleep(x) 会阻塞函数相应的秒数,如果按照同步的方式,总共应该是6秒,而通过协程,其实实现了异步,时间变为4秒!

import asyncio
import time

start = time.time()
# 协程函数
async def do_some_work(x):
    print('Waiting: ', x)
    await asyncio.sleep(x)
    return 'Done after {}s'.format(x)

# 协程对象
coroutine1 = do_some_work(2)
coroutine3 = do_some_work(4)

# 将协程转成task,并组成list
tasks = [
    asyncio.ensure_future(coroutine1),
    asyncio.ensure_future(coroutine3)
]

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

for task in tasks:
    print('Task ret: ', task.result())

print("time_consume:", time.time() - start)

----------
Waiting:  2
Waiting:  4
Task ret:  Done after 2s
Task ret:  Done after 4s
time_consume: 4.002617359161377

「Python异步编程-先吃个面包」就写到这里,希望你们读了之后能有面包那种饱腹感我就心满意足了。

其实关于yield,生成器,协程有很多概念没将明白,只是抽出了自己觉得比较重要的,更加全面的教程可以看这里(良心推荐):
Python进阶开发之路

另外,廖雪峰大大的教程也可以作为辅助性教程

「Python异步编程-1」总览全局
「Python异步编程-2」可迭代对象、迭代器、生成器
「Python异步编程-3」协程、生成器、yield 的联系
「Python异步编程-4」-协程的工作流程

相关文章

  • 「Python异步编程-3」协程、生成器、yield 的联系

    异步编程的基础在于理解协程,而协程的基础在于理解生成器,而生成器的基础在于理解yield关键字,下面就来说说这几个...

  • 2018-12-16 协程

    协程 又叫微线程,纤程python 对协程的实现是通过generator实现的 生成器-含有yield 有函数-生...

  • 一文搞懂 Python 中的 yield

    关注公众号「Python七号」,及时 get Python 技能。 yield 可以实现生成器,可以实现协程。 什...

  • python协程2:yield from 从入门到精通

    上一篇python协程1:yield的使用介绍了: 生成器作为协程使用时的行为和状态 使用装饰器预激协程 调用方如...

  • Python中协程(coroutine)和生成器(generat

    协程和生成器都使用yield关键字。但是协程更像是对生成器语法的一些扩展 在生成器中, yield 只对外产出值 ...

  • yield小测试题

    前面提到了协程,就会想起协程的基础-生成器,想起生成器就会想到yield。那就顺便记下这个yield的小测试题,每...

  • Gevent高并发网络库精解

    进程 线程 协程 异步 并发编程(不是并行)目前有四种方式:多进程、多线程、协程和异步。 多进程编程在python...

  • PHP高级用法

    一、迭代器 二、生成器 三、yield 四、协程

  • Python协程深入理解

    从语法上来看,协程和生成器类似,都是定义体中包含yield关键字的函数。yield在协程中的用法:在协程中yiel...

  • Python协程深入理解

    从语法上来看,协程和生成器类似,都是定义体中包含yield关键字的函数。yield在协程中的用法: 在协程中yie...

网友评论

      本文标题:「Python异步编程-3」协程、生成器、yield 的联系

      本文链接:https://www.haomeiwen.com/subject/bsvcoftx.html