繁体   English   中英

Python的pickle / cpickle / dill可以加速进口吗?

[英]Can Python's pickle/cpickle/dill speed up imports?

pickle / dill / cpickle可以用来腌制进口模块以提高进口速度吗? 例如,Shapely模块在我的系统上花了5秒钟来查找并加载所有必需的依赖项,我真的很想避免。

我可以腌制一次进口,然后重复使用那种泡菜,而不是每次都要慢速进口吗?

不。首先,你不能挑选模块,你会得到一个错误:

>>> 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必须:

  1. 找到模块的位置(通常是文件系统上的文件)
  2. 将源代码解析为内存中的字节代码(如果可能,将解析后的字节代码存储为.pyc文件 ),或者直接将.pyc加载到内存中(如果存在)
  3. 执行模块首次加载时应运行的任何代码

如果你以某种方式挑选一个模块,你基本上会用自己的半生不熟的解决方案替换第2步。

  1. 找到pickle的位置(通常是文件系统上的文件)
  2. 将其取回到Python模块中
  3. 执行模块首次加载时应运行的任何代码

我们可以放心地假设unpickling会比Python的内置字节码格式慢,因为如果不是Python,那么无论如何都会在封面下使用pickle。

更重要的是,解析Python文件并不(非常)昂贵,并且几乎不需要任何时间。 任何真正的减速都会发生在第3步,我们没有改变。 您可能会问是否有某种方法可以跳过第三步进行酸洗,但在一般情况下没有,这是不可能的,因为没有办法保证模块不会对环境的其余部分进行更改。

现在您可能会对Shapely模块有所了解,特别是让您说“在运行之间可以安全地缓存导入时Shapely所做的所有工作”。 在这种情况下,正确的行动方案是将这种缓存行为贡献给库并缓存数据 Shapely正在加载,而不是Python正在导入的代码

虽然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.'
>>> 

导入延迟很可能是由于加载了GEOS库的相关共享对象。

可能会优化这一点,但这将非常困难。 一种方法是构建一个静态编译的自定义python解释器,内置所有DLL和扩展模块。但保持这将是一个主要的PITA(相信我 - 我这样做是为了工作)。

另一个选择是将您的应用程序转换为服务,因此只会产生启动解释器一次的运行时成本。

如果这是合适的,这取决于您的实际问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM