當前位置:
首頁 > 知識 > 一個故事講完進程、線程和協程

一個故事講完進程、線程和協程

來自:碼農翻身(微信號:coderising)



很久以前,有兩個程序,暫且稱他們旺財和小強吧。





旺財和小強這兩個程序都很長,每個都有十幾萬行。 他們兩個的人生價值就是到CPU上去運行,把運行結果告訴人類。




CPU是稀缺資源,只有一個,他們倆必須排著隊,輪流使用。




旺財從頭到尾執行完了,讓出CPU, 讓小強從頭兒去執行。




人類把這種處理方式叫做

批處理





進程




長久以來,兩人相安無事。 後來CPU的速度越來越快, 遠遠超過了內存,硬碟的速度。



人類想到,這批處理系統的效率有點低啊,你看當小強需要從硬碟上讀取數據的時候,CPU也一直在等待,這是多大的浪費啊!這時候完全可以讓旺財來運行一下嘛!




當然得保存好小強的

執行現場

:具體執行到那一行程序指令了, 函數調用到什麼層次了,每個函數調用都有什麼樣的參數,CPU寄存器中的值..... 等等一系列東西。




如果不把小強的執行現場給保存下來,等到小強的數據從銀盤讀完了,就沒法回到中斷處來繼續執行了。




這個執行現場,再加上小強的代碼,就是一個執行中的程序,被稱為「

進程

」 。



旺財和小強在運行的時候,也被改造成了進程。




人類還規定:進程不能長時間佔據CPU, 只能在CPU上執行一小會兒,然後馬上切換到別的進程去執行。




旺財和小強不以為意:不就是執行一會兒,歇一會兒,然後繼續執行嘛!







但是他們不知道的是,由於CPU運行速度超快,旺財和小強雖然在不斷地切換運行,在人類那緩慢的世界裡看來,旺財和小強好像是同時在執行一樣。  這就是

並發




(在人類看來,小強和旺財似乎是在同時執行)




多年以後,他們倆才真正地實現了

並行

: 在一個豪華電腦中,每人都被分配了一個CPU , 真正地同時執行, 這是後話了。



線程




這時候旺財已經有了界面,還能訪問網路,每當它聯網的時候(這也是個非常非常耗時的操作),就得把CPU讓給小強。




即使旺財再次被調度執行,由於網路數據還沒有返回,他必須等待,什麼事情都做不了,在人類看來,界面根本無法操作,旺財不響應了!  氣得人類經常把旺財kill掉。




旺財心裡苦,他很納悶小強怎麼就沒有問題,小強不是要讀寫硬碟嗎? 那也是很慢的操作啊。




小強說:「你傻啊,內部只有一個執行的流程,一遇到耗時的操作就得等待,你看看我,內部搞了兩個執行流程(

線程

),一個用來讀寫硬碟(T1),另外一個處理界面(T2)。我和操作系統商量好了,如果T1在讀寫硬碟, 就可以調度我的T2來執行,這樣界面至少還可以操作。 」





旺財覺得很有意思,也採用了類似辦法。




於是,一個進程中至少有一個執行的流程(主線程),也可以開啟新的執行流程(線程)。




線程變成了最小的調度單位。



協程




這一天,旺財被一個叫做生產者和消費者的問題折騰地死去活來,兩個線程,一個線程向隊列中放數據,另外一個從隊列中取數據,處理起兩個線程的協作就顯得很麻煩,不但需要加鎖,還得做好線程的通知和等待。




正在感慨多線程編程之難的時候, 旺財震驚地發現,小強用了一個極為簡單的辦法把生產者,消費者問題給解決了。




這個方法的代碼如下:

# 生產者


def

producer

(c)

:

 
   

#其他代碼  


   

while

True

:          
       value = ...生成數據...
       c.send(value)

# 消費者


def

consumer

()

:

   
   

#其他代碼      


   

while

True

:
       value =

yield


       print(value)

c = consumer()
producer(c)




「這....這怎麼執行啊,那個yield是怎麼回事?」  旺財表示不解。





「簡單啊,你看那個生產者,是不是向消費者發送了數據? 」 小強說。




「對啊,然後呢,生產者發送了數據以後,會馬上進行下一輪循環嗎?」




「這就是關鍵所在了,」小強說,「 它們是這麼執行的:」






  1. 生產者發送數據,暫停運行,不進行下一輪循環



  2. 消費者其實一直在value = yield 那裡等待,直到數據到來,現在數據來了,取出處理(value就是生產者發送過來的數據)。



  3. 消費者在循環中再次yield, 暫停執行。



  4. 生產者繼續下一輪的循環,生成新的消息,發送給消費者。






旺財覺得很吃驚,小強竟然

可以讓一個正在執行的程序暫停

,他不由得問道:「你這個暫停是真的停止了了,還是說只是像Java的yield那樣,讓出CPU進入了就緒狀態? 等待下次調度運行?」




「是真的暫停了,程序就停在那裡,等待運行控制權從對方那裡轉移過來。」




「這不是操作系統乾的事情嗎? 」 旺財更加吃驚了。




「正是這樣,」 小強得意地說:「我打算把類似生產者,消費者這樣的代碼稱為『

協程

』, 這個協程有個重要的特點,就是完全被我所調度和掌控, 不用操作系統介入。」




「這個協程和線程似乎很像啊。每次協程停止執行的時候,也得保存現場,要不然沒法恢復執行。」 旺財說。




「是啊,只是他們

比線程更加輕量級

,操作系統內核不用參與,相當於用戶態線程了,

協程的開銷極小

,可以輕鬆地創建大量的協程來做事情。 對了,也許你注意到了,我這兩個協程是"

合作式

"的,它們兩個同一時刻只能有一個在運行。 實際上,我在底層可以用一個線程去執行這兩個協程。  」




旺財表示同意:「不錯,既然兩個程序可以"合作",那就不用加鎖了,也不用在代碼里寫什麼wait和notify了,在程序層面,可以用同步的方式實現非同步的功能了! 代碼很清晰,我也搞個協程來玩玩吧!」




(完)



●編號512,輸入編號直達本文



●輸入m獲取文章目錄

推薦↓↓↓

 



運維


更多推薦:

18個技術類微信公眾號


涵蓋:程序人生、演算法與數據結構、黑客技術與網路安全、大數據技術、前端開發、Java、Python、Web開發、安卓開發、iOS開發、C/C++、.NET、Linux、資料庫、運維等。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 Linux學習 的精彩文章:

大波新特性到來,升級到 Ubuntu 18.04 LTS 的 8 大理由
21個常用Linux命令及使用案例詳解

TAG:Linux學習 |