2016-01-22 61 views
0

咸菜/莳萝/ cpickle可以用来腌制进口模块,以提高进口速度?例如,Shapely模块在我的系统上需要5秒钟才能找到并加载所有需要的依赖关系,我真的很想避免这种依赖关系。Python的pickle/cpickle/dill可以加速导入吗?

我可以腌一次我的进口,然后重新使用该酸菜,而不是每次都必须缓慢进口吗?

+1

酸洗会如何让您认为它比模块加载的标准方式更快? – dimo414

+0

如果它全部在一个文件中,那么它不必搜索大型sys.path来寻找模块。 – Brian

+1

搜索“sys,path”不太可能是显着缓慢的根源。 – BrenBarn

回答

1

号第一和formost你不能泡菜模块,你会得到一个错误:

>>> 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 file),或加载到.pyc直接存储器(如果存在)
  3. 执行是应该运行的任何代码当模块首次加载

如果您以某种方式腌制某个模块,那么您将基本上用您自己的半熟解决方案替换第2步。

  1. 找到泡菜(通常是文件系统上的文件)
  2. Unpickle它的位置返回到一个Python模块
  3. 执行是应该运行任何代码,当模块首次加载

我们可以放心地认为取消打开会比Python的内置字节码格式慢,因为如果不是Python,将会在封面下使用酸洗。

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

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

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.' 
>>> 
0

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

优化这可能可以完成,但这将是非常困难的。一种方法是构建一个静态编译的定制python解释器,其中包含所有的DLL和扩展模块。但是,坚持这将是一个主要的PITA(相信我 - 我为它工作)。

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

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