翼度科技»论坛 编程开发 python 查看内容

Generator(生成器),入门初基,Coroutine(原生协程),登峰造极,Python3.10并发

5

主题

5

帖子

15

积分

新手上路

Rank: 1

积分
15
普遍意义上讲,生成器是一种特殊的迭代器,它可以在执行过程中暂停并在恢复执行时保留它的状态。而协程,则可以让一个函数在执行过程中暂停并在恢复执行时保留它的状态,在Python3.10中,原生协程的实现手段,就是生成器,或者说的更具体一些:协程就是一种特殊的生成器,而生成器,就是协程的入门心法。
<class 'coroutine'>协程底层实现

<class 'coroutine'>我们知道,Python3.10中可以使用async和await关键字来实现原生协程函数的定义和调度,但其实,我们也可以利用生成器达到协程的效果,生成器函数和普通函数的区别在于,生成器函数使用<class 'coroutine'>yield<class 'coroutine'>语句来暂停执行并返回结果。例如,下面是一个使用生成器函数实现的简单协程:
<class 'coroutine'>
  1. def<class 'coroutine'>my_coroutine():<class 'coroutine'><class 'coroutine'>
  2. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>while<class 'coroutine'>True:<class 'coroutine'><class 'coroutine'>
  3. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>x<class 'coroutine'>=<class 'coroutine'>yield<class 'coroutine'><class 'coroutine'>
  4. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>print(x)<class 'coroutine'><class 'coroutine'>
  5. <class 'coroutine'><class 'coroutine'>
  6. #<class 'coroutine'>使用生成器函数创建协程<class 'coroutine'><class 'coroutine'>
  7. coroutine<class 'coroutine'>=<class 'coroutine'>my_coroutine()<class 'coroutine'><class 'coroutine'>
  8. <class 'coroutine'><class 'coroutine'>
  9. #<class 'coroutine'>启动协程<class 'coroutine'><class 'coroutine'>
  10. next(coroutine)<class 'coroutine'><class 'coroutine'>
  11. <class 'coroutine'><class 'coroutine'>
  12. #<class 'coroutine'>在协程中传入数据<class 'coroutine'><class 'coroutine'>
  13. coroutine.send(1)<class 'coroutine'><class 'coroutine'>
  14. coroutine.send(2)<class 'coroutine'><class 'coroutine'>
  15. coroutine.send(3)
复制代码
<class 'coroutine'>程序返回:
<class 'coroutine'>
  1. ➜<class 'coroutine'><class 'coroutine'>mydemo<class 'coroutine'>git:(master)<class 'coroutine'>✗<class 'coroutine'>/opt/homebrew/bin/python3.10<class 'coroutine'>"/Users/liuyue/wodfan/work/mydemo/src/test.py"<class 'coroutine'><class 'coroutine'>
  2. 1<class 'coroutine'><class 'coroutine'>
  3. 2<class 'coroutine'><class 'coroutine'>
  4. 3
复制代码
<class 'coroutine'>在上面的代码中,生成器函数<class 'coroutine'>my_coroutine<class 'coroutine'>使用了一个无限循环来实现协程的逻辑。每当调用<class 'coroutine'>send<class 'coroutine'>方法时,协程就会从<class 'coroutine'>yield<class 'coroutine'>语句处恢复执行,并将传入的参数赋值给变量<class 'coroutine'>x。
<class 'coroutine'>如此,就完成了协程执行-》阻塞-》切换-》回调的工作流模式。
<class 'coroutine'>当然,作为事件循环机制,协程服务启动可能无限期地运行,要关闭协程服务,可以使用生成器的close()方法。当一个协程被关闭时,它会生成GeneratorExit异常,该异常可以用生成器的方式进行捕获:
<class 'coroutine'>
  1. def<class 'coroutine'>my_coroutine():<class 'coroutine'><class 'coroutine'>
  2. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>try<class 'coroutine'>:<class 'coroutine'><class 'coroutine'>
  3. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>while<class 'coroutine'>True:<class 'coroutine'><class 'coroutine'>
  4. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>x<class 'coroutine'>=<class 'coroutine'>yield<class 'coroutine'><class 'coroutine'>
  5. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>print(x)<class 'coroutine'><class 'coroutine'>
  6. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>except<class 'coroutine'>GeneratorExit:<class 'coroutine'><class 'coroutine'>
  7. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>print("协程关闭")<class 'coroutine'><class 'coroutine'>
  8. <class 'coroutine'><class 'coroutine'>
  9. #<class 'coroutine'>使用生成器函数创建协程<class 'coroutine'><class 'coroutine'>
  10. coroutine<class 'coroutine'>=<class 'coroutine'>my_coroutine()<class 'coroutine'><class 'coroutine'>
  11. <class 'coroutine'><class 'coroutine'>
  12. #<class 'coroutine'>启动协程<class 'coroutine'><class 'coroutine'>
  13. next(coroutine)<class 'coroutine'><class 'coroutine'>
  14. <class 'coroutine'><class 'coroutine'>
  15. #<class 'coroutine'>在协程中传入数据<class 'coroutine'><class 'coroutine'>
  16. coroutine.send(1)<class 'coroutine'><class 'coroutine'>
  17. coroutine.send(2)<class 'coroutine'><class 'coroutine'>
  18. coroutine.send(3)<class 'coroutine'><class 'coroutine'>
  19. <class 'coroutine'><class 'coroutine'>
  20. coroutine.close()
复制代码
<class 'coroutine'>程序返回:
<class 'coroutine'>
  1. ➜<class 'coroutine'><class 'coroutine'>mydemo<class 'coroutine'>git:(master)<class 'coroutine'>✗<class 'coroutine'>/opt/homebrew/bin/python3.10<class 'coroutine'>"/Users/liuyue/wodfan/work/mydemo/src/test.py"<class 'coroutine'><class 'coroutine'>
  2. 1<class 'coroutine'><class 'coroutine'>
  3. 2<class 'coroutine'><class 'coroutine'>
  4. 3<class 'coroutine'><class 'coroutine'>协程关闭<class 'coroutine'>
复制代码
<class 'coroutine'>业务场景

<class 'coroutine'>在实际业务场景中,我们也可以使用生成器来模拟协程流程,主要体现在数据的IO流操作中,假设我们需要从本地往服务器传输数据,首先建立链接对象:
<class 'coroutine'>
  1. class<class 'coroutine'>Connection:<class 'coroutine'><class 'coroutine'>
  2. <class 'coroutine'><class 'coroutine'>
  3. <class 'coroutine'><class 'coroutine'>
  4. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>def<class 'coroutine'>__init__(self,<class 'coroutine'>addr):<class 'coroutine'><class 'coroutine'>
  5. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>self.addr<class 'coroutine'>=<class 'coroutine'>addr<class 'coroutine'><class 'coroutine'>
  6. <class 'coroutine'><class 'coroutine'>
  7. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>def<class 'coroutine'>transmit(self,<class 'coroutine'>data):<class 'coroutine'><class 'coroutine'>
  8. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>print(f"X:<class 'coroutine'>{data[0]},<class 'coroutine'>Y:<class 'coroutine'>{data[1]}<class 'coroutine'>sent<class 'coroutine'>to<class 'coroutine'>{self.addr}")
复制代码
<class 'coroutine'>随后建立生成器函数:
<class 'coroutine'>
  1. def<class 'coroutine'>send_to_server(conn):<class 'coroutine'><class 'coroutine'>
  2. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>while<class 'coroutine'>True:<class 'coroutine'><class 'coroutine'>
  3. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>try:<class 'coroutine'><class 'coroutine'>
  4. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>raw_data<class 'coroutine'>=<class 'coroutine'>yield<class 'coroutine'><class 'coroutine'>
  5. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>raw_data<class 'coroutine'>=<class 'coroutine'>raw_data.split('<class 'coroutine'>')<class 'coroutine'><class 'coroutine'>
  6. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>coords<class 'coroutine'>=<class 'coroutine'>(float(raw_data[0]),<class 'coroutine'>float(raw_data[1]))<class 'coroutine'><class 'coroutine'>
  7. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>conn.transmit(coords)<class 'coroutine'><class 'coroutine'>
  8. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>except<class 'coroutine'>ConnectionError:<class 'coroutine'><class 'coroutine'>
  9. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>print("链接丢失,进行回调")<class 'coroutine'><class 'coroutine'>
  10. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>conn<class 'coroutine'>=<class 'coroutine'>Connection("重新连接v3u.cn")
复制代码
<class 'coroutine'>利用生成器调用链接类的transmit方法进行数据的模拟传输,如果链接断开,则会触发回调重新连接,执行逻辑:
<class 'coroutine'>
  1. if<class 'coroutine'>__name__<class 'coroutine'>==<class 'coroutine'>'__main__':<class 'coroutine'><class 'coroutine'>
  2. <class 'coroutine'><class 'coroutine'>
  3. <class 'coroutine'><class 'coroutine'>
  4. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>conn<class 'coroutine'>=<class 'coroutine'>Connection("v3u.cn")<class 'coroutine'><class 'coroutine'>
  5. <class 'coroutine'><class 'coroutine'>
  6. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>sender<class 'coroutine'>=<class 'coroutine'>send_to_server(conn)<class 'coroutine'><class 'coroutine'>
  7. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>sender.send(None)<class 'coroutine'><class 'coroutine'>
  8. <class 'coroutine'><class 'coroutine'>
  9. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>for<class 'coroutine'>i<class 'coroutine'>in<class 'coroutine'>range(1,<class 'coroutine'>6):<class 'coroutine'><class 'coroutine'>
  10. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>sender.send(f"{100/i}<class 'coroutine'>{200/i}")<class 'coroutine'><class 'coroutine'>
  11. <class 'coroutine'><class 'coroutine'>
  12. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>#<class 'coroutine'>模拟链接断开<class 'coroutine'><class 'coroutine'>
  13. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>conn.addr<class 'coroutine'>=<class 'coroutine'>None<class 'coroutine'><class 'coroutine'>
  14. <class 'coroutine'><class 'coroutine'>
  15. <class 'coroutine'><class 'coroutine'>
  16. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>sender.throw(ConnectionError)<class 'coroutine'><class 'coroutine'><class 'coroutine'>
  17. <class 'coroutine'><class 'coroutine'>
  18. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>for<class 'coroutine'>i<class 'coroutine'>in<class 'coroutine'>range(1,<class 'coroutine'>6):<class 'coroutine'><class 'coroutine'>
  19. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>sender.send(f"{100/i}<class 'coroutine'>{200/i}")
复制代码
<class 'coroutine'>程序返回:
<class 'coroutine'>
  1. X:<class 'coroutine'>100.0,<class 'coroutine'>Y:<class 'coroutine'>200.0<class 'coroutine'>sent<class 'coroutine'>to<class 'coroutine'>v3u.cn<class 'coroutine'><class 'coroutine'>
  2. X:<class 'coroutine'>50.0,<class 'coroutine'>Y:<class 'coroutine'>100.0<class 'coroutine'>sent<class 'coroutine'>to<class 'coroutine'>v3u.cn<class 'coroutine'><class 'coroutine'>
  3. X:<class 'coroutine'>33.333333333333336,<class 'coroutine'>Y:<class 'coroutine'>66.66666666666667<class 'coroutine'>sent<class 'coroutine'>to<class 'coroutine'>v3u.cn<class 'coroutine'><class 'coroutine'>
  4. X:<class 'coroutine'>25.0,<class 'coroutine'>Y:<class 'coroutine'>50.0<class 'coroutine'>sent<class 'coroutine'>to<class 'coroutine'>v3u.cn<class 'coroutine'><class 'coroutine'>
  5. X:<class 'coroutine'>20.0,<class 'coroutine'>Y:<class 'coroutine'>40.0<class 'coroutine'>sent<class 'coroutine'>to<class 'coroutine'>v3u.cn<class 'coroutine'><class 'coroutine'>
  6. 链接丢失,进行回调<class 'coroutine'><class 'coroutine'>
  7. X:<class 'coroutine'>100.0,<class 'coroutine'>Y:<class 'coroutine'>200.0<class 'coroutine'>sent<class 'coroutine'>to<class 'coroutine'>重新连接v3u.cn<class 'coroutine'><class 'coroutine'>
  8. X:<class 'coroutine'>50.0,<class 'coroutine'>Y:<class 'coroutine'>100.0<class 'coroutine'>sent<class 'coroutine'>to<class 'coroutine'>重新连接v3u.cn<class 'coroutine'><class 'coroutine'>
  9. X:<class 'coroutine'>33.333333333333336,<class 'coroutine'>Y:<class 'coroutine'>66.66666666666667<class 'coroutine'>sent<class 'coroutine'>to<class 'coroutine'>重新连接v3u.cn<class 'coroutine'><class 'coroutine'>
  10. X:<class 'coroutine'>25.0,<class 'coroutine'>Y:<class 'coroutine'>50.0<class 'coroutine'>sent<class 'coroutine'>to<class 'coroutine'>重新连接v3u.cn<class 'coroutine'><class 'coroutine'>
  11. X:<class 'coroutine'>20.0,<class 'coroutine'>Y:<class 'coroutine'>40.0<class 'coroutine'>sent<class 'coroutine'>to<class 'coroutine'>重新连接v3u.cn
复制代码
<class 'coroutine'>如此,我们就可以利用生成器的“状态保留”机制来控制网络链接突然断开的回调补救措施了。
<class 'coroutine'>所以说,协程就是一种特殊的生成器:
<class 'coroutine'>
  1. async<class 'coroutine'>def<class 'coroutine'>test():<class 'coroutine'><class 'coroutine'>
  2. <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>pass<class 'coroutine'><class 'coroutine'>
  3. <class 'coroutine'><class 'coroutine'>
  4. print(type(test()))<class 'coroutine'>
复制代码
<class 'coroutine'>您猜怎么着?
<class 'coroutine'>
  1. <class 'coroutine'>
复制代码
<class 'coroutine'>结语

<class 'coroutine'>诚然,生成器和协程也并非完全是一个概念,与生成器不同的是,协程可以被另一个函数(称为调用方)恢复执行,而不是只能由生成器本身恢复执行。这使得协程可以用来实现更复杂的控制流,因为它们可以在执行时暂停并在任意时刻恢复执行。

来源:https://www.cnblogs.com/v3ucn/p/17009372.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】<class 'coroutine'>我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具