eventlet,django,requests问题杂记
最近使用django+requests+eventlet做了个小程序,eventlet用来替代原生的多线程,最后发现有关manage.py的功能全都不能用了,报错信息类似:
1 | django.db.utils.DatabaseError: DatabaseWrapper objects created in a thread can only be used in that same thread. The object with alias 'default' was created in thread id 139911009593152 and this is thread id 51055504. |
产生这个问题的原因在于我的monky_patch()是在爬虫模块中执行,而希望这个爬虫模块能够保持独立性不希望和django融合的太深,所以解决问题只需根据实际需求在manage.py或settings.py或wsgi.py中先把monkey_patch()执行了即可。
这个问题解决后,我打开了eventlet的源码目录,发现monkey_patch()函数本质上仅仅对一些系统库进行了修改,比如我们可以输出already_patched来看哪些模块被修改了:
1 | import eventlet |
结果如下:
1 | 1 |
可以看出,monkey_patch对上面模块进行了修改。
根据文档,如果仅想给一个模块打补丁,则可以使用import_patched()函数,所以写出下面的代码:
1 | import eventlet |
可是结果并不是想像中的样子:
1 | False |
什么鬼!?是我打开的方式不对?换成系统库,把requests换成os结果居然也是一样的,换言之——用import_patched()函数并没生效!?其实并不是这样的,我们可以看is_monkey_patched函数代码如下:
1 | def is_monkey_patched(module): |
注释解释的很清楚,如果我们使用其他的方式import模块(包括inmport_pached)这个函数并不一定返回正确的值。关键就在于already_patched这个字典的值什么时候被改变了,通过源码发现这个字典只有在monkey_patch()函数中才会被修改,这也就解释了上面的疑问。那么怎么确定import_patched函数确实生效了呢?对于requests这个模块我们可以这样:
1 | import requests |
上面的3行代码可以毫无警告的正常执行,而:
1 | import eventlet |
虽然也会正常执行,但是会产生一个警告:
1 | RuntimeWarning: Parent module 'requests' not found while handling absolute import from netrc import netrc, NetrcParseError |
如果和我一样有强迫症的话,可以改成requests = eventlet.patcher.import_patched('requests.__init__')
就不会有警告了。