繁体   English   中英

cython 字典访问导致分段错误

[英]cython dict access results in segmentation fault

我正在尝试在 cython 中实现一个简单的缓存方法。 编译通过了,但在运行时读取缓存使程序因分段错误而崩溃。

这是我的 cython hello.pyx文件

# disutils: language = C++
# define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
cimport libc.stdint
cimport cython
cimport numpy as np
from libc.stdio cimport printf
from libcpp.unordered_map cimport unordered_map
from libcpp.pair cimport pair
from cython.operator cimport dereference

np.import_array()  # needed to initialize numpy-API

cdef class DemoClass:
    cdef readonly unordered_map[double, double[:]] cache

    def __init__(self):
        cdef unordered_map[double, double[:]] cache
        self.cache = cache

    cpdef double[:] demoMethod(self, double key):

        if self.cache.count(key) > 0:
            printf("second time")
            return self.cache[key]

        printf("First time")
        cdef double[:] result = cnp_empty(100)
        self.cache[key] = result

        return result

这是我试图在 python 中运行的

from hello import DemoClass

import numpy as np
demoObj2 = DemoClass()
print(demoObj2.demoMethod(0.0)) # <MemoryView of 'ndarray' object>
print(demoObj2.demoMethod(0.0)) # this results in Segmentation fault, no more messages

我用错了无序地图的哪一点?


编辑:大卫的回答启发了我去尝试别的东西

from hello import DemoClass

import numpy as np
demoObj2 = DemoClass()
a = demoObj2.demoMethod(0.0)
print(a) # <MemoryView of 'ndarray' object>
print(demoObj2.demoMethod(0.0)) # this works fine now, because the reference to the memoryview is now kept, in python.

不能将内存视图存储在无序映射中。 memoryview 是 Cython 管理的引用计数类型,C++ 无序映射不知道 memoryview 的引用计数或初始化。

Cython 3.0 alpha 将对此进行诊断并发出错误消息以阻止您这样做。 但是旧版本的 Cython 不会。

无序地图不适合您的目标。 Python dict 会更好(尽管它存储了 memoryview 的“非类型化”Python 包装器,因此对于速度而言并不理想)。 但是,实际上,您最好将原始 Numpy 数组存储在字典中,而不是这些数组的内存视图。

正如@DavidW 所回答的,一旦返回结果memoryview ,如果没有引用它的 python 代码,python 将对该对象进行垃圾清理,导致缓存指向已删除的数据。

AFAIK,有两种方法可以解决这个问题。

  1. 使用from cpython.ref cimport Py_INCREF to Py_INCREF在缓存时手动增加 python 对 memoryview result的引用。 这意味着 GIL 被收购了。
  2. 不使用 memory_view,而是使用 libcpp.vector。 这不是 python 垃圾清理,所以它不需要引用 inc 并且可以在没有 gil 的情况下完成。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM