4

我正在尝试使用 numpy memmap 使用一个非常大的 numpy 数组,将每个元素作为 ctypes 结构访问。

class My_Structure(Structure):
    _fields_ = [('field1', c_uint32, 3),
                ('field2', c_uint32, 2),
                ('field3', c_uint32, 2),
                ('field4', c_uint32, 9),
                ('field5', c_uint32, 12),
                ('field6', c_uint32, 2),
                ('field7', c_uint32, 2)]

    def __str__(self):
        return f'MyStruct -- f1{self.field1} f2{self.field2} f3{self.field3} f3{self.field4} f5{self.field5} f6{self.field6} f7{self.field7}'

    def __eq__(self, other):
        for field in self._fields_:
            if getattr(self, field[0]) != getattr(other, field[0]):
                return False
            return True

_big_array = np.memmap(filename = 'big_file.data',
                                   dtype = 'uint32',
                                   mode = 'w+',
                                   shape = 1000000
                                   )

big_array = _big_array.ctypes.data_as(ctypes.POINTER(My_Structure))

big_array[0].field1 = 5
...

它似乎工作正常,但我在 python.exe 停止的 64 位 Windows 机器上遇到了错误。在事件查看器中,我看到错误模块名称是_ctypes.pyd,异常代码是 0xc0000005,我认为这是一个访问异常。

我在 Linux 上似乎没有遇到同样的错误,尽管我的测试并不彻底。

我的问题是:

  1. 我的访问权限是否正确;IE。我使用numpy.memmap.ctypes.data_as正确吗?

  2. __str__我定义了函数 (和__eq__)的事实会My_Structure改变它的大小吗?IE。它仍然可以在数组中用作uint32吗?

  3. 您认为有什么可能会导致这种行为吗?特别考虑到 Windows 和 Linux 之间的差异?

编辑:

  1. 在 big_array 元素上使用ctypes.addressofand ctypes.sizeof,看起来__str__and__eq__不会影响My_Structure

  2. 我在访问之前添加了一些断言big_array,发现我正在尝试访问big_array[-1],这解释了访问错误和崩溃。

这让问题 1 悬而未决:看起来我的代码在技术上是正确的,但我想知道是否有比使用 ctypes.pointer 更好的方法来访问 numpy 数组,这样我仍然可以获得使用 numpy 数组的好处(越界访问警告、负索引换行等)。下面的 Daniel 建议使用结构化的 numpy 数组,但是可以用它来进行位域访问吗?

4

1 回答 1

0

您可以ctypes在最后一步转换为,而不是第一步:

_big_array[0, ...].ctypes.data_as(ctypes.POINTER(My_Structure)).field1 = 5

请注意,...需要将结果保持为 0d 数组,以便.ctypes属性存在

现在当然,负索引可以正常工作:

_big_array[-1, ...].ctypes.data_as(ctypes.POINTER(My_Structure)).field1 = 5

下面的 Daniel 建议使用结构化的 numpy 数组,但是可以用它来进行位域访问吗?

于 2018-11-19T08:10:07.030 回答