python—協程

協程的概念:

協程: 協助程序,線程和進程都是搶佔式特點,線程和進程的切換我們是不能參與的。

而協程是非搶佔式特點,協程也存在着切換,這種切換是由我們用戶來控制的。

協程主解決的是IO的操作。

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

協程的優點:

優點1: 協程極高的執行效率。因爲子程序切換不是線程切換,而是由程序自身控制,

因此,沒有線程切換的開銷,和多線程比,線程數量越多,協程的性能優勢就越明顯。

優點2: 不需要多線程的鎖機制,因爲只有一個線程,也不存在同時寫變量衝突,

在協程中控制共享資源不加鎖,只需要判斷狀態就好了,所以執行效率比多線程高很多。

因爲協程是一個線程執行,那怎麼利用多核CPU呢?簡單的方法是多進程+協程,既充分利用多核,又充分發揮協程的高效率,可獲得極高的性能。

yield的簡單實現

yield的功能類似於return,但是不同之處在於它返回的是生成器。

生成器是通過一個或多個yield表達式構成的函數,每一個生成器都是一個迭代器(但是迭代器不一定是生成器)。

如果一個函數包含yield關鍵字,這個函數就會變成一個生成器。

生成器並不會一次返回所有的結果,而是每次遇到yield關鍵字後返回相應的結果,並保留函數當前的運行狀態,等待下一次的調用。

由於生成器也是一個迭代器,那麼他就應該支持next方法來獲取下一個值。

import time
def consumer(name):
    print("消費者準備喫包子-----------")
    while  True:
        new_baozi  = yield  #接受調用生成器的值
        print("%s喫第%d個包子"%(name,new_baozi))
        time.sleep(1)

def producer(name):
    r=con.__next__()
    r=con2.__next__()

    count=1
    while True:
        print("%s正在生產f第%s個包子和第%d個包子"%(name,count,count+1))
        #調用生成器並且發送數據
        con.send(count)
        con2.send(count+1)
        count+=2
if __name__ == '__main__':
    con=consumer("翠花")
    con2=consumer("王大錘")

greenlet 模塊

greenlet是一個用C實現的協程模塊,相比與python自帶的yield,它可以使你在任意函數之間隨意切換,而不需把這個函數先聲明爲generator

安裝 :pip3 install greenlet。如果引入的時候還是報錯,使用pycharm進行下載


from greenlet  import greenlet
def work1():
  print(12)
  gr2.switch()
  print(45)
  gr2.switch()


def work2():
    print(89)
    gr1.switch()
    print(43)


#  1.將要執行的函數封裝到greenlet對象中
gr1 = greenlet(work1)
gr2 = greenlet(work2)
#   2.想先執行那個函數就可以使用    對象,swith()方法進行執行
gr1.switch()

結果:

12
89
45
43

gevent模塊

Gevent 是一個第三方庫,可以輕鬆通過gevent實現併發同步或異步編程,

在gevent中用到的主要模式是Greenlet, 它是以C擴展模塊形式接入Python的輕量級協程。

Greenlet全部運行在主程序操作系統進程的內部,但它們被協作式地調度。

import time
import  requests
import gevent
def f(url):
    print("get",url)
    resp=requests.get(url)
    data = resp.text
    print("%d bytes received  from %s"%(len(data),url))


# 1.普通模式
s=time.time()
f("http://www.langlang2017.com/img/banner1.png")
f("http://www.langlang2017.com/img/banner2.png")
f("http://www.langlang2017.com/img/banner3.png")
f("http://www.langlang2017.com/img/banner4.png")
e=time.time()
print("普通模式時間",e-s)


#   2.使用gevent模塊
start = time.time()
gevent.joinall([gevent.spawn(f,"http://www.langlang2017.com/img/banner1.png"),
                gevent.spawn(f, "http://www.langlang2017.com/img/banner2.png"),
                gevent.spawn(f, "http://www.langlang2017.com/img/banner3.png"),
                gevent.spawn(f, "http://www.langlang2017.com/img/banner4.png")])#創建一個普通的greenlet對象並切換

print("gevent時間",time.time()-start)
"""
如果量小的話串行比gevent
"""

結果:

get http://www.langlang2017.com/img/banner1.png
396098 bytes received  from http://www.langlang2017.com/img/banner1.png
get http://www.langlang2017.com/img/banner2.png
666248 bytes received  from http://www.langlang2017.com/img/banner2.png
get http://www.langlang2017.com/img/banner3.png
665348 bytes received  from http://www.langlang2017.com/img/banner3.png
get http://www.langlang2017.com/img/banner4.png
755635 bytes received  from http://www.langlang2017.com/img/banner4.png
普通模式時間 34.99790930747986
get http://www.langlang2017.com/img/banner1.png
396098 bytes received  from http://www.langlang2017.com/img/banner1.png
get http://www.langlang2017.com/img/banner2.png
666248 bytes received  from http://www.langlang2017.com/img/banner2.png
get http://www.langlang2017.com/img/banner3.png
665348 bytes received  from http://www.langlang2017.com/img/banner3.png
get http://www.langlang2017.com/img/banner4.png
755635 bytes received  from http://www.langlang2017.com/img/banner4.png
gevent時間 32.77941083908081

如果量小的話串行比gevent模塊花費時間可能少
如果大量數據就能顯示出他的性能了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章