一、概述
協(xié)程 ,又稱為微線程,它是實(shí)現(xiàn)多任務(wù)的另一種方式,只不過是比線程更小的執(zhí)行單元。因?yàn)樗詭PU的上下文,這樣只要在合適的時(shí)機(jī),我們可以把一個(gè)協(xié)程切換到另一個(gè)協(xié)程。
通俗的理解: 在一個(gè)線程中的某個(gè)函數(shù)中,我們可以在任何地方保存當(dāng)前函數(shù)的一些臨時(shí)變量等信息,然后切換到另外一個(gè)函數(shù)中執(zhí)行,注意不是通過調(diào)用函數(shù)的方式做到的 ,并且切換的次數(shù)以及什么時(shí)候再切換到原來的函數(shù)都由開發(fā)者自己確定。
協(xié)程擁有自己的寄存器和棧。協(xié)程調(diào)度切換的時(shí)候,將寄存器上下文和棧都保存到其他地方,在切換回來的時(shí)候,恢復(fù)到先前保存的寄存器上下文和棧,因此:協(xié)程能保留上一次調(diào)用狀態(tài),每次過程重入時(shí),就相當(dāng)于進(jìn)入上一次調(diào)用的狀態(tài)。
協(xié)程的好處:
1.無需線程上下文切換的開銷(還是單線程)
2.無需原子操作(一個(gè)線程改一個(gè)變量,改一個(gè)變量的過程就可以稱為原子操作)的鎖定和同步的開銷
3.方便切換控制流,簡(jiǎn)化編程模型
4.高并發(fā)+高擴(kuò)展+低成本:一個(gè)cpu支持上萬的協(xié)程都沒有問題,適合用于高并發(fā)處理
協(xié)程缺點(diǎn):
1.無法利用多核的資源,協(xié)程本身是個(gè)單線程,它不能同時(shí)將單個(gè)cpu的多核用上,協(xié)程需要和進(jìn)程配合才能運(yùn)用到多cpu上(協(xié)程是跑在線程上的)
2.進(jìn)行阻塞操作時(shí)會(huì)阻塞掉整個(gè)程序:如io
協(xié)程與線程的差異:
在實(shí)現(xiàn)多任務(wù)時(shí), 線程切換從系統(tǒng)層面遠(yuǎn)不止保存和恢復(fù)CPU上下文這么簡(jiǎn)單。操作系統(tǒng)為了程序運(yùn)行的高效性,每個(gè)線程都有自己緩存Cache等等數(shù)據(jù),操作系統(tǒng)還會(huì)幫你做這些數(shù)據(jù)的恢復(fù)操作,所以線程的切換非常耗性能。但是協(xié)程的切換只是單純地操作CPU的上下文,所以一秒鐘切換個(gè)上百萬次系統(tǒng)都抗的住。
二、協(xié)程工作過程
1. yield工作原理
從語(yǔ)法上來看,協(xié)程和生成器類似,都是定義體中包含yield關(guān)鍵字的函數(shù)。
1. yield在協(xié)程中的用法:
- 在協(xié)程中yield通常出現(xiàn)在表達(dá)式的右邊,例如:datum = yield,可以產(chǎn)出值,也可以不產(chǎn)出--如果yield關(guān)鍵字后面沒有表達(dá)式,那么生成器產(chǎn)出None。
- 在協(xié)程中yield也可能從調(diào)用方接受數(shù)據(jù),調(diào)用方是通過send(datum)的方式把數(shù)據(jù)提供給協(xié)程使用,而不是next(...)函數(shù),通常調(diào)用方會(huì)把值推送給協(xié)程。
- 協(xié)程可以把控制器讓給中心調(diào)度程序,從而激活其他的協(xié)程。
所以總體上在協(xié)程中把yield看做是控制流程的方式。
2. 協(xié)程在運(yùn)行過程中有四個(gè)狀態(tài):
- GEN_CREATE:等待開始執(zhí)行
- GEN_RUNNING:解釋器正在執(zhí)行,這個(gè)狀態(tài)一般看不到
- GEN_SUSPENDED:在yield表達(dá)式處暫停
- GEN_CLOSED:執(zhí)行結(jié)束
import time
def task_1():
while True:
print("--This is task 1!--before")
yield
print("--This is task 1!--after")
time.sleep(0.5)
def task_2():
while True:
print("--This is task 2!--before")
yield
print("--This is task 2!--after")
time.sleep(0.5)
if __name__ == "__main__":
t1 = task_1() # 生成器對(duì)象
t2 = task_2()
# print(t1, t2)
while True:
next(t1) # 1、喚醒生成器t1,執(zhí)行到y(tǒng)ield后,保存上下文,掛起任務(wù);下次再次喚醒之后,從yield繼續(xù)往下執(zhí)行
print("\nThe main thread!\n") # 2、繼續(xù)往下執(zhí)行
next(t2) # 3、喚醒生成器t2,....
運(yùn)行結(jié)果如下:
三、實(shí)現(xiàn)協(xié)程的方式
- yield
- yield from
- greenlet庫(kù)實(shí)現(xiàn)協(xié)程
- gevent庫(kù)實(shí)現(xiàn)協(xié)程
- asyncio異步協(xié)程
https://blog.csdn.net/weixin_41599977/article/details/93656042