Python 如果我有足够的内存,如何加快取消勾选大型对象的速度?

Python 如果我有足够的内存,如何加快取消勾选大型对象的速度?,python,serialization,pickle,Python,Serialization,Pickle,使用cPickle(将其作为二进制pickle文件存储在磁盘上时为1GB)读取1GB的NetworkX图形数据结构需要花费我一个小时的时间 请注意,文件会快速加载到内存中。换句话说,如果我跑步: import cPickle as pickle f = open("bigNetworkXGraph.pickle","rb") binary_data = f.read() # This part doesn't take long graph = pickle.loads(binary_data

使用cPickle(将其作为二进制pickle文件存储在磁盘上时为1GB)读取1GB的NetworkX图形数据结构需要花费我一个小时的时间

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

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)时都尝试过对数据进行酸洗,而我使用的协议似乎没有太大区别。还要注意的是,尽管我使用了上面的“加载”(意思是“加载字符串”)函数,但它加载的是二进制数据,而不是ascii数据


我正在使用的系统上有128gb的RAM,所以我希望有人能告诉我如何在pickle实现中增加一些读取缓冲区。

为什么不使用
pickle.load

f = open('fname', 'rb')
graph = pickle.load(f)

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

抱歉,无法通过pickle模块自动拆分数据,所以您必须自己完成


无论如何,另一种方法(相当困难)是使用类似的方法来存储数据…

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

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

当然,你也应该花同样多的时间优化你的数据结构,以最小化你想要存储的数据的数量和复杂性。

这太荒谬了

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

写下来大约需要3分钟。
我在16分钟的时候就停止了阅读,我的公羊完全窒息了

我现在使用的是marshal,它需要: 写:~3s
阅读:~5s

我拨弄了一下,发现了这个。
我想我从未看过pickle源代码,但它构建了一个完整的VM来重建字典?

在文档IMHO中应该有一个关于超大对象性能的注释。

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


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

我还试图加快networkx图的加载/存储速度。我正在使用该方法将图形转换为可序列化的内容,例如,请参见以下代码:

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)
然而,这种
邻接图
转换方法非常慢,因此在酸洗过程中获得的时间可能会在转换过程中损失

所以这实际上并没有加快速度,笨蛋。运行此代码将提供以下计时:

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
这种指数增长可能是由于图的边数呈指数增长。这里有一个测试要点,以防你想亲自尝试


我使用cPickle本身读取了大约750MB的igraph数据结构(一个二进制pickle文件)。这是通过简单地结束前面提到的pickle加载调用来实现的

您案例中的示例代码段如下所示:

将cPickle作为pickle导入
导入gc
f=打开(“bigNetworkXGraph.pickle”、“rb”)
#禁用垃圾收集器
gc.disable()
图形=pickle.load(f)
#再次启用垃圾收集器
gc.enable()
f、 关闭()
这肯定不是最合适的方法,但是,它大大减少了所需的时间。

(对我来说,它从843.04秒减少到41.28秒,大约20倍)

他有128GB的RAM,为什么他要进行所有的拆分?不,我的意思是128GB-这是一台大机器。我也有24个核可以使用,所以一个并行的解决方案会很好,虽然我猜GIL不会真的让这成为可能。哇!大机器:)对不起,误会了!这可能不会有帮助;阅读部分速度足够快,并且有足够的内存,所以直接从流中取消勾选不会获得太多。这是我尝试的第一件事。我展示了加载pickle文件的更复杂的方法,以说明将二进制数据读入ram似乎不是瓶颈。你真的是指128GB的ram吗?或者128MB?好吧,我可以想出一些方法在某种程度上分解这些数据(将节点属性放在不同的文件中),但是图形对象的边缘本身就占用了大量内存——如果我必须将这些存储在不同的文件中,并且每次使用它时都重新填充图形,那么序列化的意义何在?我也可以将图形数据存储在一个边缘列表中。我确实不认为序列化是解决问题的最佳方法。Pickle从来就不适合用于大型数据结构。这更像是支持随机访问和按需加载的类似数据库的格式。为什么需要再次启用gc?协议为4的Python3的pickle会更有效吗?@alvas在默认情况下保持gc启用不是一个好的实践吗?另外,我还没有尝试过Python3中的protocol=4,但我没有尝试过上面的场景。@Tejassah您是否偶然将其与joblib进行了比较?我用一个joblib加载完成了这项工作,同时切换和不切换垃圾收集。“这个”链接已经不存在了。差不多10年后?不足为奇。我想你只需要相信我的话,或者自己做基准。