我正在尝试找到一种节省空间的方法来在 Python 中存储类似结构的对象。
# file point.py
import collections
Point = collections.namedtuple('Point', ['x', 'y'])
这是 cythonized 版本:
# file cpoint.pyx
cdef class CPoint:
cdef readonly int x
cdef readonly int y
def __init__(self, int x, int y):
self.x = x
self.y = y
def __repr__(self):
return 'Point(x={}, y={})'.format(self.x, self.y)
我希望 cythonized 版本的内存效率更高:
from pympler.asizeof import asizeof
from point import Point
from cpoint import CPoint
asizeof(Point(1,2)) # returns 184
asizeof(CPoint(1,2)) # returns 24
但令人惊讶的是,尽管有静态类型和更轻的内存表示,但 cythonized 版本在 pickled 时占用了更多空间。
import pickle
len(pickle.dumps(Point(1,2))) # returns 28
len(pickle.dumps(CPoint(1,2))) # returns 70
是否有更有效的方法来序列化这样的 cython 对象?
后续
我想要保留各个 CPoint
对象的原因是因为我在流应用程序中接收异构 CPoint
类对象,因此我需要缓冲它们位于异构类型的列表
中。
如果我们能保证列表元素的类型,那么确实可以使用 numpy 数组来改善存储空间。我们也有可能通过同质容器获得更好的压缩属性,但您必须放弃序列化非结构化数据的多功能性。
在容纳非结构化数据的同时,依靠@ead和@DavidW提出的同质容器的空间优势的一种算法解决方案是存储前面对象位置的位图(假设我们知道所有可能的类型)在字节码编译时传入对象(这是一个广泛的假设),然后仍然将对象分组在同质容器中。也许可以通过以面向列的方式对它们进行排序来进一步提高效率,以便压缩可以更好地提高效率。如果没有基准测试,很难说。
最佳答案
这并不是专门的 Cython 解决方案,但是:如果您担心磁盘上的大小,那么您可能有很多这样的解决方案。在这种情况下,一个不错的选择是将数据存储在 numpy structured array 中。以避免创建大量 Python 对象(或者可能是 Pandas 之类的对象)。
我还希望对对象的数组/numpy 列表进行pickle 比对单个对象进行pickle 更有用(我相信当你有很多对象时,pickle 会进行一些优化)同样的事情)
import collections
from cpoint import CPoint
Point = collections.namedtuple('Point', ['x', 'y'])
l = [ Point(n,n) for n in range(10000) ]
l2 = [ CPoint(n,n) for n in range(10000) ]
import numpy as np
l3 = np.array(list(zip(list(range(10000)), list(range(10000)))),
dtype=[('x',int),('y',int)])
import pickle
print("Point",len(pickle.dumps(l))/20000)
print("CPoint",len(pickle.dumps(l2))/20000)
print("nparray",len(pickle.dumps(l3))/20000)
打印:
Point 9.9384
CPoint 16.4402
nparray 8.01215
namedtuple
和 numpy.array
版本都非常接近我们期望的每个 int 8 字节的限制,但 numpy 数组版本更好。
有趣的是,如果我们在调用中添加 protocol=pickle.HIGHEST_PROTOCOL
,那么一切都会进一步改善,并且 namedtuple
版本再次令人信服地获胜。 (我怀疑它注意到它不需要完整的 64 位整数来存储,并且我怀疑这是否很容易手动击败)
Point 5.9775
CPoint 10.47975
nparray 8.0107
关于python - 在 Python 中对 Cython 对象进行空间高效的 pickle ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50660112/