cython内存不足

时间:2019-01-13 12:06:25

标签: memory-management cython

我正在尝试在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)

我需要创建一个list的Python BitSet(大约12_000),每个大小为1_000_000。我想这应该占用1_000_000位(以存储Bint类型)* 12000 = 1.5 GB

但是我的内存快要用完了,这里有一张图片来解释更多

enter image description here

曲线的最低点为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整数集替换BitSet可以,但是它要慢得多,并且应该占用更多空间)

1 个答案:

答案 0 :(得分:1)

bint只是一个方便的整数类型,可用于存储true / false值。与所有其他C类型一样,它需要具有一个可以以整个字节为单位进行度量的地址,因此它至少占用1个字节(实际上,它看起来更多)。

为了以节省空间的方式存储布尔值,您需要存储整数类型,然后进行一些操作以访问单个元素:

cdef uint8_t x = some_value
nth_element_is_true = bool(x & (1<<n)) # bitshift to get a suitable mask then bitwise and

您显然可以将其扩展为使用数组来存储多个元素。


存在一些明显的预制可能性:

首先,您可以使用numpy.packbitsunpackbits。不过,这确实会产生相当昂贵的临时变量(例如unpackbits将创建一个大小为8倍的数组)。

第二,您可以使用std::vector<bool>,它已经过优化,每个元素使用1位:

from libcpp.vector cimport vector
from libcpp cimport bool
cdef vector[bool] vb = vector[bool](1000000)

创建专门的vector<bool>的行为与正常vector的行为不同,在C ++中,这是一个不好的主意,但是它可以做什么你想要的。