python 生成器与协程的关系和区别

部分摘录自官方中文文档,python 版本 3.7.4

注意概念区分:生成器函数,生成器,协程函数,协程,异步生成器函数,异步生成器

主要是学习笔记,没有进行过多整理

  • 使用 async def 语法定义的函数总是为协程函数,即使它们不包含 await 或 async 关键字,另外 await,async for 以及 async with 只能在协程函数体中使用(注:以普通函数调用方式调用协程函数时,将返回协程对象,而不是运行协程)

  • 在一个函数体内使用 yield 表达式会使这个函数变成一个生成器,并且在一个 async def 定义的函数体(注:协程函数)内使用 yield 表达式会让协程函数变成异步的生成器(注:以普通函数调用方式调用生成器函数时,将返回生成器对象,而不是运行生成器;以普通函数调用方式调用异步生成器函数时,将返回异步生成器对象,而不是运行异步生成器)

  • 生成器函数与协程(注:函数)非常相似,它们 yield 多次,它们具有多个入口点,并且它们的执行可以被挂起。唯一的区别是生成器函数不能控制在它在 yield 后交给哪里继续执行,控制权总是转移到生成器的调用者

  • 当使用 yield from 时,它会将所提供的表达式视为一个子迭代器,这个子迭代器产生的所有值都直接被传递给当前生成器方法的调用者

  • 启动一个生成器的方法有两种,注意,这两种调用都有返回值,返回的是生成器 yield 的值:

    • 使用内建的 next() 函数,继续使用 next() 函数将继续运行生成器
    • 使用生成器的 send() 方法,但启动时必须传参 None,继续调用 send() 方法将继续运行生成器,此时可以向生成器传入任意值
  • 启动一个协程的方法:导入 asyncio 包,使用 asyncio.run() 函数执行一个协程,注意,需要传入协程对象作为参数,而不是协程函数

  • 注意,await 语句返回指定协程 return 的值(与生成器的 yeild 有区别)

  • 如果只有一个协程在运行的话,代码执行流程与普通函数一样,因为协程函数中的 await <指定协程> 语句将会挂起(阻塞)当前协程,去执行 await 语句指定的协程,直到指定协程执行结束返回后才恢复当前协程

  • 可以使用 asyncio.gather() 函数并发执行多个协程