天天看點

python程序線程協程差別_python 程序、線程與協程的差別

程序、線程與協程差別總結

- 1.程序是電腦最小資源配置設定機關

- 2.線程是CPU排程的最小機關

- 3.程序切換需要的資源很最大,效率很低

- 4.線程切換需要的資源一般,效率一般(當然了在不考慮GIL的情況下)

- 5.協程切換任務資源很小,效率高(協程本身并不存在,是程式員通過控制IO操作完成)

- 6.多程序、多線程根據cpu核數不一樣可能是并行的,但是協程是在一個線程中 是以是并發

程序:一個運作的程式(代碼)就是一個程序,沒有運作的代碼叫程式,程序是系統資源配置設定的最小機關,程序擁有自己獨立的記憶體空間,是以程序間資料不共享,開銷大。

線程: 排程執行的最小機關,也叫執行路徑,不能獨立存在,依賴程序存在一個程序至少有一個線程,叫主線程,而多個線程共享記憶體(資料共享,共享全局變量),進而極大地提高了程式的運作效率。

協程:是一種使用者态的輕量級線程,協程的排程完全由使用者控制。協程擁有自己的寄存器上下文和棧。 協程排程切換時,将寄存器上下文和棧儲存到其他地方,在切回來的時候,恢複先前儲存的寄存器上下文和棧,直接操作棧則基本沒有核心切換的開銷,可以不加鎖的通路全局變量,是以上下文的切換非常快。

什麼是多線程競争?

線程是非獨立的,同一個程序裡線程是資料共享的,當各個線程通路資料資源時會出現競争狀态即:

資料幾乎同步會被多個線程占用,造成資料混亂 ,即所謂的線程不安全

那麼怎麼解決多線程競争問題?-- 鎖。

鎖的好處:

確定了某段關鍵代碼(共享資料資源)隻能由一個線程從頭到尾完整地執行能解決多線程資源競争下的原子操作問題。

鎖的壞處:

阻止了多線程并發執行,包含鎖的某段代碼實際上隻能以單線程模式執行,效率就大大地下降了,鎖的緻命問題:死鎖

多程序

在Linux系統下,使用os.fork(), 調用一次,傳回兩次,作業系統自動把目前程序(父程序)複制了一份(子程序),然後分别在父程序和子程序内傳回。子程序永遠傳回0,父程序傳回子程序的ID。經過這樣做,父程序就能fork出很多子程序,并可以記錄下子程序的ID号了,子程序可以通過getppid()來擷取父程序ID。fork()僅在Unix/Linux下使用,windows則不行。 是以,在Python中,存在一個跨平台的包mutiprocessing,通過引入包中的Process類,就可以建立多程序程式了,可以建立一個程序p=Process(target=func,args=(*,)),然後利用p.start()及p.join()來執行了。以上的join()方法可以等待子程序結束後才往下執行,通常用于程序間同步。 另外,可以用程序池的方式,例如p=Pool(n),然後p.apply_async(func,args),這裡可以使用n種不同的參數傳入,建立不同的程序。用這種方式時,在調用join()方法前,要先調用close()方法,使得不能再添加新程序。 mutiprocessing包裡提供了Queue、Pipe等多種程序間通信的方法。可以直接引入Queue類,然後執行個體化一個對象。則不同的程序可以使用put方法發資訊,同時可以使用get方法取資訊。

多線程

多個任務可以建立多個程序來完成,同時也可以建立多個線程來完成,線程是作業系統直接的執行單元。 Python含有threading這個進階子產品,要啟動一個線程,就是把一個函數傳出并建立Thread執行個體,然後調用start()方法開始執行,例如t=threading.Thread(target=func,name=*),注意這裡的name屬性,它是給線程命名的,預設值為Thread-1···。要注意的是,剛才說了,任何一個程序都含有一個線程,而這個主線程則執行着我們編寫的程式,可以調用threading.current_thread().name來檢視它,它的名字就叫MainThread。 在多線程程式設計中,有一個最大的問題就在于程序内的資源被各個線程所共享,程序内任何變量都可以被任何一個線程修改,是以,線程之間若去修改同一個變量,則可能導緻程式Bug。是以,引入了鎖機制。 當某個線程去修改某個變量時,可以在變量所在的方法内加一把鎖,使得其他線程不能同時執行該方法,隻有釋放了鎖後,其他線程才能去獲得鎖并獲得修改權。建立一個鎖是通過lock=threading.Lock()來實作的,可以使用try···finally···語句,在try之前使用lock.acquire()獲得鎖,然後在try語句裡面修改變量,然後在finally語句裡加lock.release()來保證鎖一定被釋放,避免成為一個死鎖。

差別于聯系

多程序的優點是穩定性好,一個子程序崩潰了,不會影響主程序以及其餘程序。但是缺點是建立程序的代價非常大,因為作業系統要給每個程序配置設定固定的資源,并且,作業系統對程序的總數會有一定的限制,若程序過多,作業系統排程都會存在問題,會造成假死狀态。

多線程優點是效率較高一些,但是緻命的缺點是任何一個線程崩潰都可能造成整個程序的崩潰,因為它們共享了程序的記憶體資源池。 對于任務數來說,無論是多程序或者多線程,都不能太多。因為作業系統在切換任務時,會有一系列的保護現場措施,這要花費相當的系統資源,若任務過多,則大部分資源都被用做幹這些了,結果就是所有任務都做不好,是以作業系統會限制程序的數量。 另外,考慮計算密集型及IO密集型應用程式。對于計算密集型,多任務勢必造成資源浪費。對于IO密集型,因為IO速度遠低于CPU計算速度,是以使用多任務方式可以大大增大程式運作效率。

協程,又稱微線程 英文名Coroutine

協程是python個中另外一種實作多任務的方式,隻不過比線程更小占用更小執行單元(了解為需要的資源)。 為啥說它是一個執行單元,因為它自帶CPU上下文。這樣隻要在合适的時機, 我們可以把一個協程 切換到另一個協程。 隻要這個過程中儲存或恢複 CPU上下文那麼程式還是可以運作的。

在實作多任務時, 線程切換從系統層面遠不止儲存和恢複 CPU上下文這麼簡單。 作業系統為了程式運作的高效性每個線程都有自己緩存Cache等等資料,作業系統還會幫你做這些資料的恢複操作。 是以線程的切換非常耗性能。但是協程的切換隻是單純的操作CPU的上下文,是以一秒鐘切換個上百萬次系統都抗的住。

協程 -> 微線程 在不開辟線程的情況下 完成多個任務"交替執行" 網絡爬蟲

協程是一個特殊的生成器

yield 傳回值 生成器

yield 協程(沒傳回值就是協程)

greenlet已經實作了協程,但是這個還的人工切換,是不是覺得太麻煩了,不要捉急,python還有一個比greenlet更強大的并且能夠自動切換任務的子產品gevent

其原理是當一個greenlet遇到IO(指的是input output 輸入輸出,比如網絡、檔案操作等)操作時,比如通路網絡,就自動切換到其他的greenlet,等到IO操作完成,再在适當的時候切換回來繼續執行。

由于IO操作非常耗時,經常使程式處于等待狀态,有了gevent為我們自動切換協程,就保證總有greenlet在運作,而不是等待IO