之前看的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.启动这个greenlet是通过把这个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达到了调度器的目的.