[英]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,有两种方法可以解决这个问题。
from cpython.ref cimport Py_INCREF
to Py_INCREF
在缓存时手动增加 python 对 memoryview result
的引用。 这意味着 GIL 被收购了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.