python基础 协程
說到并發編程,大家容易想到的就是:進程、線程、協程、異步IO。四者在實現上卻有共通之處,不外乎調度二字。
進程:操作系統進程系統調度,調度號:pid,基本由操作系統提供調度支持
線程:操作系統線程調度,調度號:TCB,虛擬機提供一部分支持
協程:程序自己進行調度,調度號:函數名,全部由程序自身完成。
異步IO:由消息中間件負責調度,調度號:消息隊列。
進程、線程、協程它們三個實現的是時間復用,達到邏輯上的同步;而異步IO則僅僅實現了應用的解耦合,必須要配合前面三者中的一個或多個來實現并發的處理;
下面專門講協程
協程,顧名思義就是協同合作的程序,一個程序里可以有很多協程,這些協程在主線程的調度下,表現得像是并發執行得一樣;這樣得好處就是:輕量級。
人們常說:線程是輕量級的進程;到了協程這里,我們可以說協程是最輕量級的執行單元;不會再有比協程更輕的了;一個協程可以是一個函數或者任何可調用對象,它的調度也完全由程序自身控制,因此可以將其調度開銷按照自身需要降到最低。這就是它的優勢所在。
yield 關鍵字
| def func_1(): while True: x = yield print("value:", x) if __name__ == '__main__': g = func_1() print('啟動生成器并接收返回值:', next(g)) print('啟動生成器并接收返回值:', g.send(1)) print('啟動生成器并接收返回值:', g.send(2)) print('啟動生成器并接收返回值:', next(g)) ''' 啟動生成器并接收返回值: None value: 1 啟動生成器并接收返回值: None value: 2 啟動生成器并接收返回值: None value: None 啟動生成器并接收返回值: None ''' | def func_2(): while True: x = yield 8888 print("value:", x) if __name__ == '__main__': g = func_2() print('啟動生成器并接收返回值:', next(g)) print('啟動生成器并接收返回值:', g.send(1)) print('啟動生成器并接收返回值:', g.send(2)) print('啟動生成器并接收返回值:', next(g)) ''' 啟動生成器并接收返回值: 8888 value: 1 啟動生成器并接收返回值: 8888 value: 2 啟動生成器并接收返回值: 8888 value: None 啟動生成器并接收返回值: 8888 ''' |
?
首先,如果你還沒有對yield有個初步分認識,那么你先把yield看做“return”,這個是直觀的,它首先是個return,普通的return是什么意思,就是在程序中返回某個值,返回之后程序就不再往下運行了。看做return之后再把它看做一個是生成器(generator)的一部分(帶yield的函數才是真正的迭代器),好了,如果你對這些不明白的話,那先把yield看做return,然后直接看下面的程序,你就會明白yield的全部意思了:
def func():print("in func, generator starting...")while True:res = yield 100print("res>>>>>>>:", res)if __name__ == '__main__':g = func()print('啟動生成器并接收返回值', next(g))print("***************************")print('再次啟動生成器并接收返回值', next(g))''' in func, generator starting... 啟動生成器并接收返回值 100 *************************** res>>>>>>>: None 再次啟動生成器并接收返回值 100 ''' View Code代碼運行順序解釋:
>>>func(),程序開始執行以后,由于func函數中含有yield關鍵字,所以func函數不會真正執行,而是得到一個生成器(相當于一個對象)
>>>g = func(),通過func()得到一個生成器對象后,賦值給g
>>>next(g),啟動生成器,進入func函數,打印‘in func,generator starting...’,進入循環,在yield 100處暫停,相當于return 100
>>>print('啟動生成器并接收返回值', next(g)),接收yield(return)的值,此處是yield 100,所以屏幕上打印===啟動生成器并接收返回值 100===
>>>print("***************************"),在屏幕上打印分割線
>>>next(g),程序在上次暫停位置重新啟動并執行賦值操作
? ? ? ? ? ? ? ? ? ? ?yield=None,所以res=yield,相當于res=None
? ? ? ? ? ? ? ? ? ? ?print("res>>>>>>>:", res)在屏幕上打印res>>>>>>>: None
? ? ? ? ? ? ? ? ? ? ?然后繼續循環,在yield 100處再次暫停,相當于return 100
>>>print('再次啟動生成器并接收返回值', next(g)),接收yield(return)的值,此處是yield 100,所以屏幕上打印===再次啟動生成器并接收返回值 100===
?
到這里你可能就明白yield和return的關系和區別了,帶yield的函數是一個生成器,而不是一個函數了,這個生成器有一個函數就是next函數,next就相當于“下一步”生成哪個數,這一次的next開始的地方是接著上一次的next停止的地方執行的,所以調用next的時候,生成器并不會從func函數的開始執行,只是接著上一步停止的地方開始,然后遇到yield后,return出要生成的數,此步就結束。
def func():print("in func, generator starting...")while True:res = yield 100print("res>>>>>>>:", res)if __name__ == '__main__':g = func()print('啟動生成器并接收返回值', next(g))print("***************************")print('next再次啟動生成器并接收返回值', next(g))print("***************************")print('send再次啟動生成器并接收返回值', g.send(888))''' in func, generator starting... 啟動生成器并接收返回值 100 *************************** res>>>>>>>: None next再次啟動生成器并接收返回值 100 *************************** res>>>>>>>: 888 send再次啟動生成器并接收返回值 100 ''' View Code代碼運行順序解釋:
......
>>>print("***************************"),在屏幕上打印分割線
>>>g.send(888),程序在上次暫停位置重新啟動并執行賦值操作
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?g.send(888),相當于yield=888,所以res=yield,相當于res=888,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?print("res>>>>>>>:", res)在屏幕上打印res>>>>>>>: 888,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?然后繼續循環,在yield 100處再次暫停,相當于return 100。
>>>print('send再次啟動生成器并接收返回值', g.send(888)),接收yield(return)的值,此處是yield 100,所以屏幕上打印===send再次啟動生成器并接收返回值 100===
?
send函數的概念:上面那個res的值為什么是None,這個變成了888,到底為什么,這是因為,send是發送一個參數給res的,因為上面講到,return的時候,并沒有把100賦值給res,下次執行的時候只好繼續執行賦值操作,只好賦值為None了,而如果用send的話,開始執行的時候,先接著上一次(return 100之后)執行,先把888賦值給了res,然后執行next的作用,遇見下一回的yield,return出結果后結束
?
轉載于:https://www.cnblogs.com/sniperths/p/10512654.html
總結
以上是生活随笔為你收集整理的python基础 协程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 腾讯云搭建个人博客
- 下一篇: HTML5纯Web前端也能开发直播,不用