以前咱們學習了線程,進程的概念,瞭解了在操做系統中進程使資源分配的最小單位,線程使CPU調度的最小單位,按道理來講咱們已經算是把CPU的利用率提升了不少了,可是咱們不管使建立進程仍是建立多線程來解決問題,都要消耗必定的時間來建立進程,建立線程,以及管理他們之間的切換python
咱們知道線程是基於進程來實現的,那麼基於線程來實現併發又成爲一個新的課題,即只用一個主線程(很明顯線程可利用的CPU只有一個),狀況下實現併發,這樣就能夠節省建立線程所消耗的時間了編程
協程:是單線程下的併發,又稱微線程,纖程。英文名Coroutine。一句話說明什麼是線程:協程是一種用戶態的輕量級線程,即協程是由用戶程序本身控制調度的。、多線程
一、一個線程能夠多個協程,一個進程也能夠單獨擁有多個協程,這樣python中則能使用多核CPU。併發
二、線程進程都是同步機制,而協程則是異步異步
三、協程能保留上一次調用時的狀態,每次過程重入時,就至關於進入上一次調用的狀態ide
須要強調的是:異步編程
#1. python的線程屬於內核級別的,即由操做系統控制調度(如單線程遇到io或執行時間過長就會被迫交出cpu執行權限,切換其餘線程運行) #2. 單線程內開啓協程,一旦遇到io,就會從應用程序級別(而非操做系統)控制切換,以此來提高效率(!!!非io操做的切換與效率無關)
對比操做系統控制線程的切換,用戶在單線程內控制協程的切換函數
優勢以下:學習
#1. 協程的切換開銷更小,屬於程序級別的切換,操做系統徹底感知不到,於是更加輕量級 #2. 單線程內就能夠實現併發的效果,最大限度地利用cpu
缺點以下:spa
#1. 協程的本質是單線程下,沒法利用多核,能夠是一個程序開啓多個進程,每一個進程內開啓多個線程,每一個線程內開啓協程 #2. 協程指的是單個線程,於是一旦協程出現阻塞,將會阻塞整個線程
協程是輕型線程,線程是輕型進程,協程是線程開啓就自動存在的
一個線程不會遇到阻塞,一直在使用CPU
多個線程---只能有一個線程使用CPU
協程比線程之間的切換和線程的建立銷燬所花費的時間,空間開銷都要小的多
總結協程的特色:
一、必須在只有一個單線程裏實現併發
二、修改享性數據不須要加鎖
三、用戶程序裏本身保存多個控制流的上下文棧
四、附加、一個協程遇到IO操做自動切換到其餘協程(如何實現檢測IO,yield,Greenleaf都沒法實現 就用到了gevent模塊(select機制))
from greenlet import greenlet def eat(name): print('%s eat 1' %name) g2.switch('egon') print('%s eat 2' %name) g2.switch() def play(name): print('%s play 1' %name) g1.switch() print('%s play 2' %name) g1=greenlet(eat) g2=greenlet(play) g1.switch('egon')#能夠在第一次switch時傳入參數,之後都不須要
單純的切換(在沒有io的狀況下或者沒有重複開闢內存空間的操做),反而會下降程序的執行速度
#順序執行 import time def f1(): res=1 for i in range(100000000): res+=i def f2(): res=1 for i in range(100000000): res*=i start=time.time() f1() f2() stop=time.time() print('run time is %s' %(stop-start)) #10.985628366470337 #切換 from greenlet import greenlet import time def f1(): res=1 for i in range(100000000): res+=i g2.switch() def f2(): res=1 for i in range(100000000): res*=i g1.switch() start=time.time() g1=greenlet(f1) g2=greenlet(f2) g1.switch() stop=time.time() print('run time is %s' %(stop-start)) # 52.763017892837524
greenlet只是提供了一種比generator更加便捷的切換方式,當切到一個任務執行時若是遇到io,那就原地阻塞,仍然是沒有解決遇到IO自動切換來提高效率的問題。
單線程裏的這20個任務的代碼一般會既有計算操做又有阻塞操做,咱們徹底能夠在執行任務1時遇到阻塞,就利用阻塞的時間去執行任務2。。。。如此,才能提升效率,這就用到了Gevent模塊。
安裝:pip3 install gevent
Gevent 是一個第三方庫,能夠輕鬆經過gevent實現併發同步或異步編程,在gevent中用到的主要模式是Greenlet, 它是以C擴展模塊形式接入Python的輕量級協程。 Greenlet所有運行在主程序操做系統進程的內部,但它們被協做式地調度。
g1=gevent.spawn(func,1,,2,3,x=4,y=5)建立一個協程對象g1,spawn括號內第一個參數是函數名,如eat,後面能夠有多個參數,能夠是位置實參或關鍵字實參,都是傳給函數eat的 g2=gevent.spawn(func2) g1.join() #等待g1結束 g2.join() #等待g2結束 #或者上述兩步合做一步:gevent.joinall([g1,g2]) g1.value#拿到func1的返回值