如何在有充足RAM的情况下加速大型对象的反序列化?
我用cPickle读取一个1GB的NetworkX图数据结构,竟然要花我将近一个小时(这个文件在磁盘上以二进制pickle文件存储时就是1GB)。
不过,这个文件加载到内存里是很快的。换句话说,如果我运行:
import cPickle as pickle
f = open("bigNetworkXGraph.pickle","rb")
binary_data = f.read() # This part doesn't take long
graph = pickle.loads(binary_data) # This takes ages
我该怎么加快最后这个操作的速度呢?
我注意到我尝试过用二进制协议(1和2)来打包数据,但似乎用哪种协议都没什么太大区别。另外,虽然我上面使用的是“loads”(意思是“加载字符串”)这个函数,但它实际上是在加载二进制数据,而不是ascii数据。
我使用的系统有128GB的内存,所以我希望有人能告诉我怎么增加一些在pickle实现中隐藏的读取缓冲区。
8 个回答
13
我成功地用cPickle读取了一个大约750 MB的igraph数据结构(一个二进制的pickle文件)。这个过程很简单,只需要像这里提到的那样,封装一下pickle的加载调用就可以了,具体可以参考这里。
在你的情况下,示例代码可能看起来像这样:
import cPickle as pickle
import gc
f = open("bigNetworkXGraph.pickle", "rb")
# disable garbage collector
gc.disable()
graph = pickle.load(f)
# enable garbage collector again
gc.enable()
f.close()
虽然这并不是最完美的方法,但确实大大缩短了所需的时间。
(对我来说,时间从843.04秒减少到了41.28秒,差不多快了20倍)
8
你可能是因为创建和分配Python对象的开销太大,而不是因为反序列化(unpickling)本身的问题。 如果真是这样,那你能做的事情不多,除了不一次性创建所有对象。你真的需要一次性加载整个结构吗?如果不需要的话,可以考虑懒加载数据结构(比如:用被序列化的字符串来表示结构的一部分,只有在需要的时候才进行反序列化)。