在引出協成概念之前先說說python的程序和線程。
程序:
程序是正在執行程式執行個體。執行程式的過程中,核心會講程式代碼載入虛拟記憶體,為程式變量配置設定空間,建立 bookkeeping 資料結構,來記錄與程序有關的資訊,
比如程序 id,使用者 id 等。在建立程序的時候,核心會為程序配置設定一定的資源,并在程序存活的時候不斷進行調整,比如記憶體,程序建立的時候會占有一部分記憶體。
程序結束的時候資源會釋放出來,來讓其他資源使用。我們可以把程序了解為一種容器,容器内的資源可多可少,但是在容器内的程式隻能使用容器内的東西。是以啟動
程序的時候會比較慢,尤其是windows,尤其是多程序的時候(最好是在密集性運算的時候啟動多程序)
線程:
一個程序中可以執行多個線程。多個線程共享程序内的資源。是以可以将線程可以看成是共享同一虛拟記憶體以及其他屬性的程序。
線程相對于程序的優勢在于同一程序下的不同線程之間的資料共享更加容易。
在說到線程的時候說說gil(全局解釋性鎖 global interpreter lock),gil 的存在是為了實作 python 中對于共享資源通路的互斥。而且是非常霸道的解釋器級别的互斥。在 gil 的機制下,一個線程通路解釋器之後,其他的線程就需要等待這個線程釋放之後才可以通路。這種處理方法在單處理器下面并沒有什麼問題,單處理器的本質是串行執行的。但是再多處理器下面,這種方法會導緻無法利用多核的優勢。python 的線程排程跟作業系統的程序排程類似,都屬于搶占式的排程。一個程序執行了一定時間之後,發出一個信号,作業系統響應這個時鐘中斷(信号),開始程序排程。而在 python 中,則通過軟體模拟這種中斷,來實作線程排程。比如:對全局的num做加到100的操作,可能在你加到11的時候,還沒加完,則cpu就交給另一個線程處理,是以最後的結果可能比100會小或者比100會大。
簡單的說說程序和線程的幾點關系
1、啟動一個程序至少會有一個線程
2、修改主線程的資料會影響到子線程的資料,因為他們之間記憶體是共享的,修改主程序不會影響到子程序的資料,兩個子程序之間是互相獨立的,如果要實作子程序間的通信,可以利用中間件,比如multiprocessing的queue。
如:


3、新的線程很容易被建立,但是新的程序需要對其父程序進行一次克隆
4、一個線程可以操作和控制同一個程序裡的其他線程,但程序隻能操作其子程序。
明白了程序和線程的概念之後,說說協成。
協程:
協程,又稱微線程。英文名coroutine。
協程最大的優勢就是協程極高的執行效率。因為子程式切換不是線程切換,而是由程式自身控制,是以,沒有線程切換的開銷,和多線程比,線程數量越多,協程的性能優勢就越明顯。
第二大優勢就是不需要多線程的鎖機制,因為隻有一個線程,也不存在同時寫變量沖突,在協程中控制共享資源不加鎖,隻需要判斷狀态就好了,是以執行效率比多線程高很多。
因為協程是一個線程執行,那怎麼利用多核cpu呢?最簡單的方法是多程序+協程,既充分利用多核,又充分發揮協程的高效率,可獲得極高的性能。
用yield來實作傳統的生産者-消費者模型是一個線程寫消息,一個線程取消息,通過鎖機制控制隊列和等待。


其實python有個子產品封裝了協程功能,greenlet.來看代碼。


這個還的人工切換,是不是覺得太麻煩了,不要捉急,python還有一個自動切換比greenlet更強大的gevent。
其原理是當一個greenlet遇到io操作時,比如通路網絡,就自動切換到其他的greenlet,等到io操作完成,再在适當的時候切換回來繼續執行。
由于io操作非常耗時,經常使程式處于等待狀态,有了gevent為我們自動切換協程,就保證總有greenlet在運作,而不是等待io。直接上代碼


下面我們用greenlet來實作一個socket多線程處理資料的功能。不過需要安裝一個monkey更新檔,請自行安裝吧。
client端:


server端:


以上代碼可以自行多開幾個用戶端,然後執行看看,是不是很酷,無論用戶端輸入什麼,服務端都能實時接收到。
over!