協程,又稱微線程,纖程。英文名Coroutine。一句話說明什麼是線程:協程是一種用戶態的輕量級線程。python
協程擁有本身的寄存器上下文和棧。協程調度切換時,將寄存器上下文和棧保存到其餘地方,在切回來的時候,恢復先前保存的寄存器上下文和棧。所以:編程
協程能保留上一次調用時的狀態(即全部局部狀態的一個特定組合),每次過程重入時,就至關於進入上一次調用的狀態,換種說法:進入上一次離開時所處邏輯流的位置。併發
協程的好處:異步
缺點:async
使用yield實現協程操做例子異步編程
import time def consumer(name): print("開始吃包子") while True: bun = yield #使函數掛起 print(name,"正在吃",bun) def producer(): r = con.__next__() r = con2.__next__() n = 0 while n < 5: n += 1 con.send(n) con2.send(n) time.sleep(2) print("正在製做包子",n) if __name__ == '__main__': con = consumer("alex") con2 = consumer("japhi") p = producer()
greenlet是一個用C實現的協程模塊,相比與python自帶的yield,它可使你在任意函數之間隨意切換,而不需把這個函數先聲明爲generator函數
import greenlet def main(): print("1111111") gr2.switch() print("3333333") gr2.switch() def next(): print("2222222") gr1.switch() print("4444444") if __name__ == "__main__": gr1 = greenlet.greenlet(main) #實例化一個協程對象,括號內是函數 gr2 = greenlet.greenlet(next) gr1.switch() #手動切換 輸出結果: 1111111 2222222 3333333 4444444
先實例化對象,而後調用手動切換方法switch 高併發
Gevent 是一個第三方庫,能夠輕鬆經過gevent實現併發同步或異步編程,在gevent中用到的主要模式是Greenlet, 它是以C擴展模塊形式接入Python的輕量級協程。 Greenlet所有運行在主程序操做系統進程的內部,但它們被協做式地調度。atom
import gevent def first(): print(1111) gevent.sleep(3) #模擬io切換,自動切換 print(22222) def second(): print(33333) gevent.sleep(2) #模擬io切換,自動切換 print(44444) def third(): print(55555) gevent.sleep(1) #模擬io切換,自動切換 print(666666) gevent.joinall([ #須要把函數全都加入進去 gevent.spawn(first), gevent.spawn(second), gevent.spawn(third) ]) 輸出: 1111 33333 55555 666666 44444 22222
from urllib import request import gevent,time from gevent import monkey monkey.patch_all() #添加io操做標準,讓程序能夠並行下載網頁 def net(url): resq = request.urlopen(url) data = resq.read() print(len(data)) urls = ['https://www.baidu.com/', 'https://www.hao123.com/', 'https://www.sina.com/' ] time_start = time.time() for url in urls: net(url) print("同步cost",time.time() - time_start) async_time_start = time.time() gevent.joinall([ gevent.spawn(net,"https://www.baidu.com"), gevent.spawn(net,"https://www.hao123.com"), gevent.spawn(net,"https://www.sina.com/") ]) print("異步cost",time.time() - async_time_start) 輸出結果: 227 514581 601335 同步cost 2.6131491661071777 227 514599 601338 異步cost 2.2071263790130615
異步並行所花的時間少於同步,但要加 monkey.patch_all() #添加io操做標準,讓程序能夠並行下載網頁url