01. 協(xié)程基礎(chǔ)

一、概述

協(xié)程 ,又稱為微線程,它是實現(xiàn)多任務(wù)的另一種方式,只不過是比線程更小的執(zhí)行單元。因為它自帶CPU的上下文,這樣只要在合適的時機,我們可以把一個協(xié)程切換到另一個協(xié)程。
通俗的理解: 在一個線程中的某個函數(shù)中,我們可以在任何地方保存當(dāng)前函數(shù)的一些臨時變量等信息,然后切換到另外一個函數(shù)中執(zhí)行,注意不是通過調(diào)用函數(shù)的方式做到的 ,并且切換的次數(shù)以及什么時候再切換到原來的函數(shù)都由開發(fā)者自己確定。
協(xié)程擁有自己的寄存器和棧。協(xié)程調(diào)度切換的時候,將寄存器上下文和棧都保存到其他地方,在切換回來的時候,恢復(fù)到先前保存的寄存器上下文和棧,因此:協(xié)程能保留上一次調(diào)用狀態(tài),每次過程重入時,就相當(dāng)于進入上一次調(diào)用的狀態(tài)。
協(xié)程的好處:
1.無需線程上下文切換的開銷(還是單線程)
2.無需原子操作(一個線程改一個變量,改一個變量的過程就可以稱為原子操作)的鎖定和同步的開銷
3.方便切換控制流,簡化編程模型
4.高并發(fā)+高擴展+低成本:一個cpu支持上萬的協(xié)程都沒有問題,適合用于高并發(fā)處理
協(xié)程缺點:
1.無法利用多核的資源,協(xié)程本身是個單線程,它不能同時將單個cpu的多核用上,協(xié)程需要和進程配合才能運用到多cpu上(協(xié)程是跑在線程上的)
2.進行阻塞操作時會阻塞掉整個程序:如io
協(xié)程與線程的差異:
在實現(xiàn)多任務(wù)時, 線程切換從系統(tǒng)層面遠不止保存和恢復(fù)CPU上下文這么簡單。操作系統(tǒng)為了程序運行的高效性,每個線程都有自己緩存Cache等等數(shù)據(jù),操作系統(tǒng)還會幫你做這些數(shù)據(jù)的恢復(fù)操作,所以線程的切換非常耗性能。但是協(xié)程的切換只是單純地操作CPU的上下文,所以一秒鐘切換個上百萬次系統(tǒng)都抗的住。

二、協(xié)程工作過程

1. yield工作原理

從語法上來看,協(xié)程和生成器類似,都是定義體中包含yield關(guān)鍵字的函數(shù)。

1. yield在協(xié)程中的用法:

  • 在協(xié)程中yield通常出現(xiàn)在表達式的右邊,例如:datum = yield,可以產(chǎn)出值,也可以不產(chǎn)出--如果yield關(guān)鍵字后面沒有表達式,那么生成器產(chǎn)出None。
  • 在協(xié)程中yield也可能從調(diào)用方接受數(shù)據(jù),調(diào)用方是通過send(datum)的方式把數(shù)據(jù)提供給協(xié)程使用,而不是next(...)函數(shù),通常調(diào)用方會把值推送給協(xié)程。
  • 協(xié)程可以把控制器讓給中心調(diào)度程序,從而激活其他的協(xié)程。
    所以總體上在協(xié)程中把yield看做是控制流程的方式。

2. 協(xié)程在運行過程中有四個狀態(tài):

  • GEN_CREATE:等待開始執(zhí)行
  • GEN_RUNNING:解釋器正在執(zhí)行,這個狀態(tài)一般看不到
  • GEN_SUSPENDED:在yield表達式處暫停
  • 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()  # 生成器對象
    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,....

運行結(jié)果如下:


運行結(jié)果

三、實現(xiàn)協(xié)程的方式

  • yield
  • yield from
  • greenlet庫實現(xiàn)協(xié)程
  • gevent庫實現(xiàn)協(xié)程
  • asyncio異步協(xié)程

https://blog.csdn.net/weixin_41599977/article/details/93656042

https://www.cnblogs.com/luyuze95/p/11294695.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容