Generator(生成器),入门初基,Coroutine(原生协程),登峰造极,Python3.10并发
|
普遍意义上讲,生成器是一种特殊的迭代器,它可以在执行过程中暂停并在恢复执行时保留它的状态。而协程,则可以让一个函数在执行过程中暂停并在恢复执行时保留它的状态,在Python3.10中,原生协程的实现手段,就是生成器,或者说的更具体一些:协程就是一种特殊的生成器,而生成器,就是协程的入门心法。
<class 'coroutine'>协程底层实现
<class 'coroutine'>我们知道,Python3.10中可以使用async和await关键字来实现原生协程函数的定义和调度,但其实,我们也可以利用生成器达到协程的效果,生成器函数和普通函数的区别在于,生成器函数使用<class 'coroutine'>yield<class 'coroutine'>语句来暂停执行并返回结果。例如,下面是一个使用生成器函数实现的简单协程:
<class 'coroutine'>- def<class 'coroutine'>my_coroutine():<class 'coroutine'><class 'coroutine'>
- <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>while<class 'coroutine'>True:<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'>
- <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>print(x)<class 'coroutine'><class 'coroutine'>
- <class 'coroutine'><class 'coroutine'>
- #<class 'coroutine'>使用生成器函数创建协程<class 'coroutine'><class 'coroutine'>
- coroutine<class 'coroutine'>=<class 'coroutine'>my_coroutine()<class 'coroutine'><class 'coroutine'>
- <class 'coroutine'><class 'coroutine'>
- #<class 'coroutine'>启动协程<class 'coroutine'><class 'coroutine'>
- next(coroutine)<class 'coroutine'><class 'coroutine'>
- <class 'coroutine'><class 'coroutine'>
- #<class 'coroutine'>在协程中传入数据<class 'coroutine'><class 'coroutine'>
- coroutine.send(1)<class 'coroutine'><class 'coroutine'>
- coroutine.send(2)<class 'coroutine'><class 'coroutine'>
- coroutine.send(3)
复制代码 <class 'coroutine'>程序返回:
<class 'coroutine'>- ➜<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'>
- 1<class 'coroutine'><class 'coroutine'>
- 2<class 'coroutine'><class 'coroutine'>
- 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'>- def<class 'coroutine'>my_coroutine():<class 'coroutine'><class 'coroutine'>
- <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>try<class 'coroutine'>:<class 'coroutine'><class 'coroutine'>
- <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>while<class 'coroutine'>True:<class 'coroutine'><class 'coroutine'>
- <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'>
- <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'>
- <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>except<class 'coroutine'>GeneratorExit:<class 'coroutine'><class 'coroutine'>
- <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'>
- <class 'coroutine'><class 'coroutine'>
- #<class 'coroutine'>使用生成器函数创建协程<class 'coroutine'><class 'coroutine'>
- coroutine<class 'coroutine'>=<class 'coroutine'>my_coroutine()<class 'coroutine'><class 'coroutine'>
- <class 'coroutine'><class 'coroutine'>
- #<class 'coroutine'>启动协程<class 'coroutine'><class 'coroutine'>
- next(coroutine)<class 'coroutine'><class 'coroutine'>
- <class 'coroutine'><class 'coroutine'>
- #<class 'coroutine'>在协程中传入数据<class 'coroutine'><class 'coroutine'>
- coroutine.send(1)<class 'coroutine'><class 'coroutine'>
- coroutine.send(2)<class 'coroutine'><class 'coroutine'>
- coroutine.send(3)<class 'coroutine'><class 'coroutine'>
- <class 'coroutine'><class 'coroutine'>
- coroutine.close()
复制代码 <class 'coroutine'>程序返回:
<class 'coroutine'>- ➜<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'>
- 1<class 'coroutine'><class 'coroutine'>
- 2<class 'coroutine'><class 'coroutine'>
- 3<class 'coroutine'><class 'coroutine'>协程关闭<class 'coroutine'>
复制代码 <class 'coroutine'>业务场景
<class 'coroutine'>在实际业务场景中,我们也可以使用生成器来模拟协程流程,主要体现在数据的IO流操作中,假设我们需要从本地往服务器传输数据,首先建立链接对象:
<class 'coroutine'>- class<class 'coroutine'>Connection:<class 'coroutine'><class 'coroutine'>
- <class 'coroutine'><class 'coroutine'>
- <class 'coroutine'><class 'coroutine'>
- <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>def<class 'coroutine'>__init__(self,<class 'coroutine'>addr):<class 'coroutine'><class 'coroutine'>
- <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'>
- <class 'coroutine'><class 'coroutine'>
- <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>def<class 'coroutine'>transmit(self,<class 'coroutine'>data):<class 'coroutine'><class 'coroutine'>
- <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'>- def<class 'coroutine'>send_to_server(conn):<class 'coroutine'><class 'coroutine'>
- <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>while<class 'coroutine'>True:<class 'coroutine'><class 'coroutine'>
- <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>try:<class 'coroutine'><class 'coroutine'>
- <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'>
- <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'>
- <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'>
- <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'>
- <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>except<class 'coroutine'>ConnectionError:<class 'coroutine'><class 'coroutine'>
- <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'>
- <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'>- if<class 'coroutine'>__name__<class 'coroutine'>==<class 'coroutine'>'__main__':<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'><class 'coroutine'>
- <class 'coroutine'><class 'coroutine'>
- <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>sender<class 'coroutine'>=<class 'coroutine'>send_to_server(conn)<class 'coroutine'><class 'coroutine'>
- <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>sender.send(None)<class 'coroutine'><class 'coroutine'>
- <class 'coroutine'><class 'coroutine'>
- <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'>
- <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'>
- <class 'coroutine'><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.addr<class 'coroutine'>=<class 'coroutine'>None<class 'coroutine'><class 'coroutine'>
- <class 'coroutine'><class 'coroutine'>
- <class 'coroutine'><class 'coroutine'>
- <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>sender.throw(ConnectionError)<class 'coroutine'><class 'coroutine'><class 'coroutine'>
- <class 'coroutine'><class 'coroutine'>
- <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'>
- <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'>- 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'>
- 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'>
- 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'>
- 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'>
- 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'><class 'coroutine'>
- 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'>
- 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'>
- 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'>
- 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'>
- 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'>- async<class 'coroutine'>def<class 'coroutine'>test():<class 'coroutine'><class 'coroutine'>
- <class 'coroutine'><class 'coroutine'><class 'coroutine'><class 'coroutine'>pass<class 'coroutine'><class 'coroutine'>
- <class 'coroutine'><class 'coroutine'>
- print(type(test()))<class 'coroutine'>
复制代码 <class 'coroutine'>您猜怎么着?
<class 'coroutine'><class 'coroutine'>结语
<class 'coroutine'>诚然,生成器和协程也并非完全是一个概念,与生成器不同的是,协程可以被另一个函数(称为调用方)恢复执行,而不是只能由生成器本身恢复执行。这使得协程可以用来实现更复杂的控制流,因为它们可以在执行时暂停并在任意时刻恢复执行。
来源:https://www.cnblogs.com/v3ucn/p/17009372.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】<class 'coroutine'>我们会及时删除侵权内容,谢谢合作! |
|
|
|
发表于 2023-1-2 16:09:45
举报
回复
分享
|
|
|
|