前言介紹
協程 ,又稱為微線程,它是實現多任務的另一種方式,只不過是比線程更小的執行單元。因為它自帶CPU的上下文,這樣只要在合適的時機,我們可以把一個協程切換到另一個協程。通俗的理解: 在一個線程中的某個函數中,我們可以在任何地方保存當前函數的一些臨時變量等信息,然后切換到另外一個函數中執行,注意不是通過調用函數的方式做到的 ,並且切換的次數以及什么時候再切換到原來的函數都由開發者自己確定。
協程與線程的差異:
在實現多任務時, 線程切換從系統層面遠不止保存和恢復CPU上下文這么簡單。操作系統為了程序運行的高效性,每個線程都有自己緩存Cache等等數據,操作系統還會幫你做這些數據的恢復操作,所以線程的切換非常耗性能。但是協程的切換只是單純地操作CPU的上下文,所以一秒鍾切換個上百萬次系統都抗的住。
下面舉例說明協程和線程使用過程中CPU消耗情況
1、創建線程測試文件 threads.py,代碼內容如下:
import time from threading import Thread def hello(x): """測試任務""" for i in range(50): print(f'測試線程{x}') time.sleep(1) # 模擬 def thread_test(): """創建1000個線程並進行任務""" for i in range(1000): Thread(target=hello, args=(i,)).start() if __name__ == '__main__': thread_test()
2、創建協程測試文件 gevents.py,代碼內容如下:
import gevent from gevent import monkey monkey.patch_all() import time def hello(x): """測試任務""" for i in range(50): print(f'測試協程{x}') time.sleep(1) def gevent_test(): """創建1000個協程任務""" gevent.joinall([gevent.spawn(hello, i) for i in range(1000)]) if __name__ == '__main__': gevent_test()
運行結果:
結論:開啟1000個線程任務所消耗的CPU是13.5%,開啟1000個協程任務消耗的CPU是 1.1%,協程遠優於線程
眾所周知 ,多線程除了會給cpu帶來切換上下文的開銷,還會產生資源競爭,想要用多線程,免不了加鎖操作,協程完美的避免了這個問題。
所以在多線程和協程都能適用的場景下,協程是一個更好的選擇。