cython ctypedef 大型双数组导致 Ubuntu 18.04 上的段错误


ctypedef struct ReturnRows:
double[50000] v1
double[50000] v2
double[50000] v3
double[50000] v4

有效,但是

ctypedef struct ReturnRows:
double[100000] v1
double[100000] v2
double[100000] v3
double[100000] v4

失败并显示Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)

这对我来说没有意义,因为上限应该接近专用于该处理任务的系统的可用限制。是否以某种方式设置了上限?

这是我的构建器:

from distutils.core import setup
import numpy as np
from distutils.core import setup, Extension
from Cython.Build import cythonize
file_names = ['example_cy.pyx', 'enricher_cy.pyx']
for fn in file_names:
print("cythonize %s" % fn)
setup(ext_modules = cythonize(fn),
author='CGi',
author_email='hi@so.com',
description='Utils for faster data enrichment.',
packages=['distutils', 'distutils.command'],
include_dirs=[np.get_include()])

来自问题:我如何使用结构?我从熊猫数据帧迭代它:

cpdef ReturnRows cython_atrs(list v1, list v2, list v3, list v4):
cdef ReturnRows s_ReturnRows # Allocate memory for the struct

s_ReturnRows.v1 = [0] * 50000
s_ReturnRows.v2 = [0] * 50000
s_ReturnRows.v3 = [0] * 50000
s_ReturnRows.v4 = [0] * 50000
# tmp counters to keep track of the latest data averages and so on.
cdef int lines_over_v1 = 0
cdef double all_ranges = 0
cdef int some_index = 0

for i in range(len(v3)-1):
# trs
s_ReturnRows.v1[i] = (round(v2[i] - v3[i],2))
# A lot more calculations, why I really need this loop.

正如链接的问题@ead建议的那样,解决方案是在堆上而不是堆栈上分配变量(作为函数局部变量(。原因是堆栈上的空间非常有限(在 Linux 上为 ~8MB(,而堆(通常(是 PC 上可用的任何空间。

链接的问题主要是指new/delete作为这样做C++方式; 虽然Cython代码可以使用C++,但C更常用,为此您可以使用malloc/free。Cython 文档在这方面非常好,但要用您问题中的代码进行演示:

from libc.stdlib cimport malloc, free    
# note some discussion about the return-value at the end of the question...
def cython_atrs(list v1, list v2, list v3, list v4):
cdef ReturnRows *s_ReturnRows # pointer, not value
s_ReturnRows = <ReturnRows*>malloc(sizeof(ReturnRows))
try:
# all your code goes here and remains the same...
finally:
free(s_ReturnRows)

您也可以使用模块级全局变量,但您可能不想这样做。

另一种选择是使用cdef class而不是结构:

cdef class ReturnRows:
double[50000] v1
double[50000] v2
double[50000] v3
double[50000] v4

这是在堆上自动分配的,内存由 Python 跟踪。


你也可以使用2D Numpy/其他Python库数组。这些也在堆上分配(但它对你隐藏(。优点是Python会跟踪内存,因此您不会忘记释放它。第二个优点是您可以轻松改变阵列大小,而不会复杂化。如果你发明了一些特别毫无意义的微基准来分配大量数组而不做任何其他事情,你可能会发现性能差异,但对于大多数普通代码,你不会。通过类型化内存视图的访问应该像 C 指针一样快。你可以找到很多比较速度/其他功能的问题,但实际上你应该选择你觉得最容易写的一个(structs可能是C,也许(。


函数中返回ReturnRows增加了复杂性(并且即使现有代码没有崩溃也会使它变得可疑(。你应该编写一个cdef函数并返回一个ReturnRows*,并将释放移动到调用函数,或者你应该编写一个def函数并返回一个有效的Python对象。这可能会将您推向 Numpy 数组作为更好的解决方案,或者可能是cdef类。

你当前的函数将做的是每当从 Python 调用它时,都会将ReturnRows转换为 Python 字典(包含数组的 Python 列表(。这可能不是你想要的。

相关内容

  • 没有找到相关文章

最新更新