python monkey_patch浅

  • 2020 年 1 月 10 日
  • 筆記

最近做了一个neutron集成vyatta的任务,顺便认真学习下neutron的代码,头几行就看到了monkey_patch。

首先就从neutron-server的启动脚本开始:

[root@controller-39 ~]# cat /usr/bin/neutron-server  #!/usr/bin/python  # PBR Generated from u'console_scripts'  import sys  from neutron.server import main  if __name__ == "__main__":      sys.exit(main())
[root@controller-39 ~]# cat /usr/lib/python2.7/site-packages/neutron/server/__init__.py  import sys  import eventlet  eventlet.monkey_patch()        #  这里使用monkey_patch    from oslo.config import cfg    from neutron.common import config  from neutron import service    from neutron.openstack.common import gettextutils  from neutron.openstack.common import log as logging  gettextutils.install('neutron', lazy=True)    LOG = logging.getLogger(__name__)    def main():

什么是monkey_patch?

简单说就是程序在运行时动态对已有代码进行修改,而不需要修改原始代码。来看个例子:

[root@controller-39 tmp]# cat monkey_patch_test.py  class Monkey_patch(object):      def patch(self):          print "patch it!"            def patch(self):      print "Modifies patch!"        Monkey_patch().patch()  Monkey_patch.patch = patch  Monkey_patch().patch()    python的namespace是开放的,通过dict来实现,所以达到patch比较容易。    python的namespace有:  1、locals  2、globals  3、builtin

一篇介绍eventlet的文章:http://www.cnblogs.com/Security-Darren/p/4170031.html

下面来看下eventlet.monkey_patch怎么用?

从上面可以看到:

eventlet.monkey_patch()  # 默认不加任何参数的情况下,是所有可能的module都会被patch。    # 看个例子  In [2]: eventlet.monkey_patch  Out[2]: <function eventlet.patcher.monkey_patch>    In [3]: eventlet.monkey_patch()    In [4]: import ti  time    timeit  timing    In [4]: import time  time    timeit    In [4]: import time    In [5]: eventlet.patcher.is_monkey_patched('time') # 查看一个module是否被monkey_patch,eventlet.patcher.is_monkey_patched(module)  Out[5]: True    In [6]: import sys    In [7]: eventlet.patcher.is_monkey_patched('sys')  # 说明eventlet没有对sys的patch  Out[7]: False    注:在程序中越早调用monkey_patch()越好,通常作为模块的第一行代码(避免子类继承父类的时候,父类还没被monkey_patch)

模块被monkey_patch后的好处:

[root@controller-39 tmp]# cat monkey_patch_test.py  #!/usr/bin/env python  import eventlet  eventlet.monkey_patch()    from eventlet.green import urllib2  import time    urls = ["http://www.tudou.com",          "http://www.baid.com"         ]             def test_1(url):      try:          print "open tudou"          time.sleep(5)          urllib2.urlopen(url).read()          print "done open tudou"      except urllib2.HTTPError:          return            def test_2(url):      try:          print "open baidu"          urllib2.urlopen(url).read()          print "done open baidu"      except urllib2.HTTPError:          return            pool = eventlet.GreenPool(100)  pool.spawn(test_1, urls[0])  pool.spawn(test_2, urls[1])  pool.waitall()    # 等待所有绿色线程执行结束    当test_1中time.sleep被调用到时,会将运行权利交给了hub,然后接着执行test_2,如果不使用monkey_patch的话time.sleep(1)会阻塞。  你可以注释掉eventlet.monkey_patch()这行代码,然后再看下运行结果。

openstack项目中大量用到了monkey_patch

[root@controller-39 tmp]# grep -n -r "eventlet.monkey_patch"   /usr/lib/python2.7/site-packages/neutron/agent/netns_cleanup_util.py:19:eventlet.monkey_patch()  /usr/lib/python2.7/site-packages/neutron/agent/l3_agent.py:20:eventlet.monkey_patch()  /usr/lib/python2.7/site-packages/oslo/messaging/_cmd/zmq_receiver.py:18:eventlet.monkey_patch()  。。。。。。