之前看的greenlet只是提供了基本的coroutine的作用,是最小的執行單元.但是要想使用,還需要提供一個調度器,來調度什麼時候哪些greenlet應該執行.所以看了一下gevent的實現,當前的穩定版本使用的是libev.libevent的替代方案.性能上更優越一些.libev支援很多事件類型,但是最常用的是io和timer類型的.io類型的通過系統提供的相關係統調用實現( linux下是epoll),timer類型的通過維護一個最小堆實現.
看一下下面的代碼:
Python代碼
import gevent from gevent import monkey monkey.patch_all() def download(): import urllib2 urllib2.urlopen('http://www.google.com/').read() c = gevent.spawn(download) gevent.joinall([c])
gevent通過spawn創建並啟動一個greenlet,此greenlet執行函數為download.greenk是透過把這個greenlet加入到libev的prepare callback裡面.libev在每次執行事件循環的時候都會調用prepare callback裡面的函數,執行後把裡面的callback清除掉.這樣就能保證每次spawn的greenlet有執行的機會.並且只會執行一次.
在這個greenlet執行urlopen以及read的時候,因為涉及到io操作(socket.[send|recv]),gevent透過monkey patch把這些函數進行了封裝,當呼叫相關的操作時就會建立一個對應fd的watcher加入libev的事件清單裡面.
當有相關的讀寫事件發生時,會觸發對應的callback.相關的callback會呼叫greenlet的switch進行coroutine的切換.
透過上面的方式greenlet達到了調度器的目的.