【发布时间】:2019-06-07 16:25:22
【问题描述】:
我正在尝试在 cython 中实现一个算法。但是我的BitSet 实现内存不足。我不知道为什么,这里是我的代码的有用快照。
bitset.pyx
# distutils: language = c++
from libcpp.vector cimport vector
cdef class BitSet:
def __cinit__(self, int size):
self.vector = vector[bint](size)
cpdef void inter(self, BitSet other) except *:
# Do the intersection in place between two bitset
cpdef void add(self, int element):
if 0 <= element < self.vector.size():
self.vector[element] = True
bitset.pxd
# distutils: language = c++
from libcpp.vector cimport vector
cdef class BitSet:
cdef public vector[bint] vector
cpdef void inter(self, BitSet other) except *
cpdef void add(self, int element)
我需要创建一个 python list 和 BitSet(大约 12_000),每个大小为 1_000_000。我会说这应该占用 1_000_000 位(存储 bint 类型)* 12000 = 1.5 GB
但是我的内存很快耗尽,这里有一张图来解释更多
曲线的最低点为 1.5 GB,最高点为 7 GB。
我用一个巨大的列表调用这个程序,这可以解释第一个峰值,第二个可能是我面临的那个。
我的程序仅在 100_000 个序列后就耗尽了内存。
这是我的主要内容:
cdef class Main:
def __cinit__(self):
self.number_sequences # Int
self.foo = [] # python list type
def train(self, sequences):
self.number_sequences = len(sequences)
for id_seq, sequence in enumerate(sequences):
for element in sequence:
while not element < len(self.foo):
self.foo.append(BitSet(self.number_sequences))
self.foo[element].add(id_seq)
我对内存使用的估计是否错误?为什么?
如何追踪我的记忆?我没有找到任何用于 cython 的工具。
有没有办法让它适合内存? (用 python 的 ints 集替换 BitSet 可以,但速度要慢得多,应该占用更多空间)
【问题讨论】:
-
bint将(至少)是一个字节而不是一个位。使用 C++std::bitset可能会更好,但我认为 Cython 没有预先编写的包装器,或者优化的std::vector<bool>,尽管我不能 100% 确定它的状态 -
我不知道。它可以解释很多事情。你怎么知道的?
-
您可以通过
print(sizeof(bint))对其进行测试(而不是信任我)。本质上,C/C++ 中的任何变量都必须占用至少一个字节。任何更有效的方案都将存储uint8_ts(或类似的),然后访问其中的各个位 - 这是bitset和vector<bool>所做的,但速度成本很小 -
....尽管请记住
sizeof以字节为单位返回答案(这暗示了所有内容的大小必须以整个字节为单位) -
经过调查,一个 bint 存储在 4 Bytes 而不是 1/8B 上。它将它乘以 32。如果您写一个答案@DavidW,我可能会接受它,我将使用 uint8_t 优化我的代码! :)