26

使用 cPickle 读取一个 1 GB 的 NetworkX 图形数据结构需要一个小时(当作为二进制文件存储在磁盘上时,它的 1 GB)。

请注意,该文件会快速加载到内存中。换句话说,如果我运行:

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 的 RAM,所以我希望有人会告诉我如何增加一些埋在 pickle 实现中的读取缓冲区。

4

8 回答 8

11

我在使用 cPickle 本身读取约 750 MB igraph 数据结构(二进制 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.04s 减少到 41.28s,大约 20 倍)

于 2016-04-18T16:58:13.953 回答
8

您可能会受到 Python 对象创建/分配开销的约束,而不是 unpickling 本身。如果是这样,除了不创建所有对象外,您几乎无法加快速度。你需要一次整个结构吗?如果没有,您可以使用数据结构的惰性填充(例如:用腌制字符串表示结构的一部分,然后仅在访问它们时才取消腌制它们)。

于 2010-05-04T15:48:06.367 回答
4

为什么不尝试使用 memcached封送数据并将其存储在 RAM 中(例如)。是的,它有一些限制,但正如指出编组比酸洗要快得多(20 到 30 倍)。

当然,您还应该花费尽可能多的时间来优化您的数据结构,以最大限度地减少您想要存储的数据的数量和复杂性。

于 2010-05-04T17:32:05.563 回答
1

这是荒唐的。

我有一个巨大的~150MB 字典(collections.Counter实际上),我正在使用二进制格式的 cPickle 进行读写。

写完大概3分钟。
我在 16 分钟时停止阅读它,我的 RAM 完全阻塞了。

我现在正在使用元帅,它需要:写:~3s
读:~5s

我翻了一下,发现了这篇文章
猜猜我从来没有看过泡菜的源代码,但它构建了一个完整的虚拟机来重建字典?
恕我直言,文档中应该有关于非常大对象的性能的说明。

于 2012-04-20T07:05:44.280 回答
1

我也在尝试加快 networkx 图的加载/存储。我正在使用该adjacency_graph方法将图形转换为可序列化的东西,例如,请参见以下代码:

from networkx.generators import fast_gnp_random_graph
from networkx.readwrite import json_graph

G = fast_gnp_random_graph(4000, 0.7)

with open('/tmp/graph.pickle', 'wb+') as f:
  data = json_graph.adjacency_data(G)
  pickle.dump(data, f)

with open('/tmp/graph.pickle', 'rb') as f:
  d = pickle.load(f)
  H = json_graph.adjacency_graph(d)

但是,这种adjacency_graph转换方法很慢,因此在酸洗中获得的时间可能会浪费在转换中。

所以这实际上并没有加快速度,真可惜。运行此代码给出以下时间:

N=1000

    0.666s ~ generating
    0.790s ~ converting
    0.237s ~ storing
    0.295s ~ loading
    1.152s ~ converting

N=2000

    2.761s ~ generating
    3.282s ~ converting
    1.068s ~ storing
    1.105s ~ loading
    4.941s ~ converting

N=3000

    6.377s ~ generating
    7.644s ~ converting
    2.464s ~ storing
    2.393s ~ loading
    12.219s ~ converting

N=4000

    12.458s ~ generating
    19.025s ~ converting
    8.825s ~ storing
    8.921s ~ loading
    27.601s ~ converting

这种指数增长可能是由于图的边缘呈指数增长。这是一个测试要点,以防您想自己尝试

https://gist.github.com/wires/5918834712a64297d7d1

于 2015-12-08T16:42:08.797 回答
0

也许你能做的最好的事情是将大数据分成比 50MB 更小的最小对象,这样可以存储在 ram 中,然后重新组合它。

Afaik 没有办法通过 pickle 模块自动拆分数据,所以你必须自己做。

无论如何,另一种方法(这是相当困难的)是使用一些像MongoDB这样的NoSQL 数据库来存储你的数据......

于 2010-05-04T15:44:41.440 回答
0

一般来说,我发现如果可能的话,在 python 中将大对象保存到磁盘时,使用 numpy ndarrays 或 scipy.sparse 矩阵会更有效。

因此,对于示例中的大型图,我可以将图转换为 scipy 稀疏矩阵(networkx 有一个函数可以做到这一点,编写一个函数并不难),然后以二进制格式保存该稀疏矩阵。

于 2012-04-22T10:40:09.920 回答
-5

你为什么不使用pickle.load

f = open('fname', 'rb')
graph = pickle.load(f)
于 2010-05-04T15:39:52.887 回答