【问题标题】:Python sort list of ctype structurectype结构的python排序列表
【发布时间】:2021-10-30 04:32:02
【问题描述】:

我的 ctype 结构如下:

class BOX(Structure):
    _fields_ = [("x", c_float),
                ("y", c_float),
                ("w", c_float),
                ("h", c_float)]

class DETECTION(Structure):
    _fields_ = [("cl", c_int),
                ("bbox", BOX),
                ("prob", c_float)]

ML 模型通过共享库传递检测结果

lib = CDLL('./libdetector.so', RTLD_GLOBAL)
detect          = lib.detect
detect.argtypes = [...]
detect.restype  = POINTER(DETECTION)

dets = detect(...)

我的代码工作正常,我检查了结果,它是正确的。但我想按其置信度分数对检测进行排序,所以我使用这一行:

_dets = sorted(dets, key=lambda det: det.prob, reverse=True)

在这一步中,我的计算机内存继续运行,当它已满时,只有“已杀”消息打印到我的控制台。那么,python sorted 是否不适用于 ctype 结构列表?我可以简单地使用for loop 进行排序,但是每个人都希望保持代码整洁美观,不是吗? :3

【问题讨论】:

  • 所以,如果它是一个POINTER(DETECTION) 结果,它不是一个列表。但是使用sorted创建一个列表,更重要的是,由ctypes.c_float对象组成,在python级别每个实例需要128字节(整个底层结构将小于一半),另外不要忘记指针的 8 个字节。因此,如果该底层数组已经非常大,这可能会增加您的内存需求...与 C 相比,Python 是一个巨大的内存猪。如果您想有效地使用结构数组,请使用 numpy

标签: python sorting ctypes


【解决方案1】:

dets 是一个指向检测结构的指针,但没有关联的大小。当传递给sorted() 时,Python 将开始迭代指针,永远将对象添加到它想要排序的列表中,甚至在访问未提交的内存时崩溃。

例子:

from ctypes import *

class BOX(Structure):
    _fields_ = [("x", c_float),
                ("y", c_float),
                ("w", c_float),
                ("h", c_float)]

class DETECTION(Structure):
    _fields_ = [("cl", c_int),
                ("bbox", BOX),
                ("prob", c_float)]

    def __init__(self,prob):  # Add some data to differentiate objects
        self.prob = prob

    def __repr__(self):       # Add a display representation
        return f'D(prob={self.prob})'

# Create a ctypes array of three DETECTION objects
a = (DETECTION * 3)(DETECTION(1.25), DETECTION(3.5), DETECTION(2.25))

# Create a pointer to the first element of the array
# simulating OP's return value from ctypes.
dets = cast(byref(a),POINTER(DETECTION))

print(dets)
print(dets[0])
print(dets[2])
_dets = sorted(dets, key=lambda det: det.prob, reverse=True) # HANGS
print(_dets)

输出:

<__main__.LP_DETECTION object at 0x000002032B7FDC40>
D(prob=1.25)
D(prob=2.25)
# On my system hangs here like OP described.

解决方法是您需要知道返回数组的大小,并将返回的指针切片为该已知大小。本例中的数组大小为 3:

_dets = sorted(dets[:3], key=lambda det: det.prob, reverse=True)

输出:

<__main__.LP_DETECTION object at 0x000001F31763DC40>
D(prob=1.25)
D(prob=2.25)
[D(prob=3.5), D(prob=2.25), D(prob=1.25)]

【讨论】:

  • 谢谢,你拯救了我的一天。要应用你的方法,我只需要提供一个长度为dets的变量,这对我来说比juanpa的方法容易。
【解决方案2】:

所以,如果它是一个POINTER(DETECTION) 结果,它不是一个列表。但是使用sorted 创建 一个列表,更重要的是,由ctypes.c_float 对象组成,每个实例需要 128 个字节,另外不要忘记 8 个字节指针。因此,如果该底层数组已经非常大,这可能会增加您的内存需求...

import numpy.ctypeslib

arr = numpy.ctypeslib.as_array(dect, shape=(n,))
arr.sort(order='prob')

其中n 必须是结果数组的大小。

请注意,生成的 numpy 结构化数组对象只是底层缓冲区的包装器。它需要少量、固定数量的辅助空间——虽然要小心,一些numpy 函数/方法可能会复制,但它不会像创建ctypes 对象列表那么糟糕!

【讨论】:

    猜你喜欢
    • 2022-01-01
    • 1970-01-01
    • 2011-07-02
    • 2022-09-28
    • 2012-12-11
    • 1970-01-01
    • 1970-01-01
    • 2015-09-01
    • 1970-01-01
    相关资源
    最近更新 更多