是一種輕量級的線程, 由程序本身控制調度的 線程是內核級的, 協程是程序級別的python
優勢:程序員
協程的切換開銷小,操做系統徹底感知不到, 單線程內就能夠實現併發效果,最大限度的 利用 CPU數組
協程遇到 IO 就自動切換到其餘協程 檢測 IO yield greenlet 沒法實現併發
用 gevent 模塊(select 機制) 實現 IO 的切換異步
僞並行,遇到IO就切換,單核下多個任務之間切換執行,給你的效果就是貌似你的幾個程序在同時執行.提升效率
任務切換 + 保存狀態async
多核cpu,真正的同時執行函數
一個任務執行完在執行另一個任務spa
進程:擁有本身獨立的堆和棧,既不共享堆,也不共享棧,進程由操做系統調度;
線程:擁有本身獨立的棧和共享的堆,共享堆,不共享棧,標準線程由操做系統調度;
協程:擁有本身獨立的棧和共享的堆,共享堆,不共享棧,協程由程序員在協程的代碼裏顯示調度。操作系統
import time '''串行 用時''' def func1(): time.sleep(1) c = 0 for i in range(1000): c = i ** i print("func1>>", c) def func2(): time.sleep(2) c = 0 for i in range(1000): c = i ** i print("func2>>", c) if __name__ == '__main__': s_t = time.time() func1() func2() print(time.time() - s_t) # 3.0608773231506348
'''基於yield併發執行,多任務之間來回切換,這就是個簡單的協程的體現,可是他可以節省I/O時間嗎?不能''' def func1(): while 1: time.sleep(1) x = yield print("接收了%s 個任務" % x) def func2(): f = func1() # 找到 第一個 yield next(f) for i in range(1, 11): f.send(i) print("發送了 %s 個任務" % i) s_t = time.time() # 基於yield保存狀態,實現兩個任務直接來回切換,即併發的效果 # PS: 若是每一個任務中都加上打印,那麼明顯地看到兩個任務的打印是你一次我一次,即併發執行的. func2() # 我在當前線程中只執行了這個函數,可是經過這個函數裏面的send切換了另一個任務 print(time.time() - s_t) # 11.003206253051758 # 串行的執行 方式 # func1() # func2() # print(time.time() - s_t) # 11.00475525856018
import time from greenlet import greenlet def eat(name): print('%s eat 1' % name) # 2 time.sleep(3) g2.switch('taibai') # 3 print('%s eat 2' % name) # 6 g2.switch() # 7 def play(name): print('%s play 1' % name) # 4 time.sleep(3) g1.switch() # 5 print('%s play 2' % name) # 8 g1 = greenlet(eat) g2 = greenlet(play) g1.switch('taibai') # 能夠在第一次switch時傳入參數,之後都不須要
import gevent from gevent import monkey monkey.patch_all() # 補丁 識別全部的 IO 阻塞 time.sleep() 就能夠用了 import time def func1(name): print(name, 111111111) time.sleep(1) # gevent.sleep(1) print(name, 2222222222) return 123 def func2(name): print(name, 111) # gevent.sleep(1) # time.sleep() 識別不到 time.sleep(1) print(name, 222) g1 = gevent.spawn(func1, "egen") # 異步執行這個func1任務,後面egon就是給他傳的參數 print(g1.value) # 取出返回值的 結果 g2 = gevent.spawn(func2, "two") # 此 方法 不用 單獨 指定 join() gevent.joinall([g1, g2]) print("aaaaaa") ################################################################ def task(pid): """ Some non-deterministic task """ time.sleep(0.5) print('Task %s done' % pid) def synchronous(): for i in range(10): task(i) def asynchronous(): g_l = [gevent.spawn(task, i) for i in range(10)] gevent.joinall(g_l) if __name__ == '__main__': print('Synchronous:') # 同步的 併發 執行 synchronous() print('Asynchronous:') # 異步的 並行 執行 asynchronous() # 上面程序的重要部分是將task函數封裝到Greenlet內部線程的gevent.spawn。 初始化的greenlet列表存放在數組threads中,此數組被傳給gevent.joinall 函數,後者阻塞當前流程,並執行全部給定的greenlet。執行流程只會在 全部greenlet執行完後纔會繼續向下走。