解释协程(coroutine)与生成器(generator)的异同。
我刚开始学 Python 的时候,最容易搞混的两个概念就是协程和生成器。看文档上都写着“用 yield 实现的”,脑子里瞬间就乱成一锅粥。后来踩了几次坑,写过点 demo,才慢慢把它们区分开。
先聊生成器
生成器你可以理解成“会记住自己运行到哪的函数”。 比如一个普通函数,调用一次跑完就结束了,对吧?但如果函数里用了 yield,它就能一边跑一边暂停,下次再跑还能接着来。
defsimple_gen():
print("step 1")
yield1
print("step 2")
yield2g = simple_gen()
print(next(g)) # 输出 step 1\n1
print(next(g)) # 输出 step 2\n2
运行的时候你会发现,它不会一次性把内容全跑完,而是每次 next() 往前推进一点点。这个特性特别适合处理大数据流,内存友好嘛。
再看协程
协程其实就是生成器的“进阶版”,但核心思想还是那个“可以暂停和恢复”的能力。区别在于:生成器主要是单向的产出数据,而协程是可以双向通信的。
举个例子:
defsimple_coro():
print("协程开始")
x = yield"ready"
print("协程收到:", x)
yield x * 2c = simple_coro()
print(next(c)) # 启动协程 -> 输出 "ready"
print(c.send(10)) # 传值进去 -> 输出 "协程收到: 10" 然后返回 20
这里的 send() 就是协程和外部交互的关键。生成器里一般是“产出”东西,而协程可以“产出 + 接收”,更灵活。
它俩的关系
底层机制:协程最早就是基于生成器语法糖 ( yield+send) 实现的,所以看起来很像。应用场景:生成器多用于“迭代、懒加载、大数据流”,协程则偏向“异步编程、事件循环”那一类。 易用性:现在大家写协程更多用 async/await,这其实是 Python 给协程专门设计的新语法,看起来更直观:
import asyncioasyncdeftask(name):
print(f"{name} start")
await asyncio.sleep(1)
print(f"{name} done")
asyncdefmain():
await asyncio.gather(task("A"), task("B"))
asyncio.run(main())
这段代码在事件循环里跑,相当于同时执行了两个任务。用生成器能做到类似的效果,但写起来就没这么舒服了。
所以啊,生成器更像是“会记忆的迭代器”,协程则是“能对话的生成器”。Python 一开始是用生成器语法来玩协程的,但随着异步需求越来越多,就干脆整了一套 async/await 体系出来。
如果你只是要处理文件、数据流,生成器就够了;要是写网络 IO、多任务调度,那协程才是正解。
-END-
我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html
虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB,点击下方公众号回复关键字 python 全部免费领