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