可以使用pickle / dill / cpickle来腌制导入的模块以提高导入速度吗?例如,Shapely模块在我的系统上花费5秒钟来查找并加载所有必需的依赖项,这是我真正想要避免的。
我可以腌制一次进口,然后重复使用那种泡菜,而不必每次都进行慢速进口吗?
答案 0 :(得分:1)
没有。首先,你不能腌制模块,你会得到一个错误:
>>> import pickle, re
>>> pickle.dump(re, open('/tmp/re.p', 'wb'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
_pickle.PicklingError: Can't pickle <class 'module'>: attribute lookup module on builtins failed
从概念上讲,即使您可以序列化模块,您也只会增加Python必须完成的工作量。
通常,当你说import module
时,Python必须:
.pyc
file),或者将.pyc
直接加载到内存中(如果存在)如果你以某种方式腌制模块,你基本上会用自己的半生不熟的解决方案替换第2步。
我们可以放心地假设unpickling比Python的内置字节码格式慢,因为如果不是Python,那么无论如何Python都会使用pickle。
更重要的是,解析Python文件并不(非常)昂贵,并且几乎不需要任何时间。任何真正的减速都会发生在第3步,我们还没有改变。您可能会问是否有某种方法可以通过酸洗来跳过第三步,但在一般情况下没有,这是不可能的,因为没有办法保证模块不能制作改变了环境的其他部分。
现在你可能知道一些关于Shapely模块的特别之处,它可以让你说&#34;导入时Shapely所做的所有工作都可以在运行之间安全地进行缓存&#34;。在这种情况下,正确的行动方针是contribute对库的缓存行为并缓存数据 Shapely正在加载,而不是Python正在导入的代码。
答案 1 :(得分:0)
虽然dill
可以序列化模块,但您可以看到它如何序列化模块,使其无法保存import
以上的工作。当dill
序列化模块时,它会调用一个函数然后导入模块。所以,正如@ dimo414所述,答案是否定的。
>>> import dill
>>> import re
>>> _re = dill.dumps(re)
>>> re_ = dill.loads(_re)
>>> re_
<module 're' from '/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/re.pyc'>
>>> _re
'\x80\x02cdill.dill\n_import_module\nq\x00U\x02req\x01\x85q\x02Rq\x03.'
>>>
答案 2 :(得分:0)
导入延迟很可能是由于加载了GEOS库的相关共享对象。
可能会对此进行优化,但这将非常困难。一种方法是构建一个内置所有DLL和扩展模块的静态编译的自定义python解释器。但保持这将是一个主要的PITA(相信我 - 我这样做是为了工作)。
另一个选择是将您的应用程序转换为服务,因此只会产生启动解释器一次的运行时成本。
如果合适,这取决于您的实际问题。