Cython中如何安全检测malloc分配的memoryview元素是否已赋值?
问题:
malloc分配的内存中安全检测已赋值元素的方法 我希望在函数中临时创建多个小型memoryview,并在函数结束时释放它们。根据对比,使用malloc初始化memoryview性能更优、速度更快,但这些小型memoryview中仅有部分元素被赋值,请问安全检测元素是否已赋值的方法是什么?
代码与性能对比
以下是使用malloc和numpy ndarray实现的代码及性能对比:
## test_malloc.pyx cimport cython import numpy as np cimport numpy as np from libc.stdlib cimport malloc, free np.import_array() @cython.wraparound(False) @cython.boundscheck(False) cdef int _num_assign_malloc(): cdef: Py_ssize_t n = 50 double *x = <double *> malloc(n * sizeof(double)) Py_ssize_t i int k = 0 x[5] = 1. x[8] = 1. x[38] = 1. for i in range(n): if x[i] == 1.: k += 1 free(x) return k @cython.wraparound(False) @cython.boundscheck(False) cdef int _num_assign_ndarray(): cdef: Py_ssize_t n = 50 double[::1] x = np.zeros(n, dtype=np.float64) Py_ssize_t i int k = 0 x[5] = 1. x[8] = 1. x[38] = 1. for i in range(n): if x[i] == 1.: k += 1 return k cpdef test_num_malloc(): return _num_assign_malloc() cpdef test_num_ndarray(): return _num_assign_ndarray()
timeit测试结果:
>>> import timeit >>> t = timeit.Timer("from test_malloc import test_num_malloc; test_num_malloc()") >>> t.timeit(10000) # 0.0111 >>> t = timeit.Timer("from test_malloc import test_num_ndarray; test_num_ndarray()") >>> t.timeit(10000) # 0.0246
未赋值元素的随机值问题
当查看malloc分配的内存中未赋值元素时,编写如下测试代码:
@cython.wraparound(False) @cython.boundscheck(False) cdef _malloc_unassign(): cdef: Py_ssize_t n = 20 double *x = <double *> malloc(n * sizeof(double)) double[::1] y = np.zeros(n, dtype=np.float64) Py_ssize_t i x[5] = 1. x[8] = 1. for i in range(n): y[i] = x[i] free(x) return y cpdef test_malloc(): return _malloc_unassign()
执行后得到结果:
>>> from test_malloc import test_malloc >>> for t in test_malloc(): ... print(t) ... 6.230420704259778e-307 3.5604305343967845e-307 1.6021930623879718e-306 2.447635570273665e-307 1.6911933005114767e-306 1.0 1.0570034520433751e-307 1.2461038328174693e-306 1.0 8.066321387750432e-308 1.201607109425611e-306 1.691193300407861e-306 1.2906222865963489e-306 1.4241722150642528e-306 1.3351264799003858e-306 7.56596412080425e-307 7.565984490202416e-307 1.6021903463576915e-306 1.424109743093715e-306 2.2250738585072396e-306
看起来可以通过x[i] == 1.来检测,但这种方式并不可靠——未赋值元素是随机值,若使用int类型,误判概率会更高。
补充:calloc方案的测试
感谢@DavidW提供的calloc方案,新增代码及性能测试如下:
@cython.boundscheck(False) @cython.wraparound(False) cdef int _num_assign_calloc(): cdef: Py_ssize_t n = 50 double *x = <double *> calloc(n, sizeof(double)) Py_ssize_t i int k = 0 x[5] = 1. x[8] = 1. x[38] = 1. for i in range(n): if x[i] == 1.: k += 1 free(x) return k
timeit测试结果:
>>> import numpy as np >>> time_malloc = [] >>> for i in range(1000): ... t = timeit.Timer("from core.test_malloc import test_num_malloc; test_num_malloc()") ... time_malloc.append(t.timeit(10000)) ... ... >>> time_ndarr = [] >>> for i in range(1000): ... t = timeit.Timer("from core.test_malloc import test_num_ndarray; test_num_ndarray()") ... time_ndarr.append(t.timeit(10000)) ... ... >>> time_calloc = [] >>> for i in range(1000): ... t = timeit.Timer("from core.test_malloc import test_num_calloc; test_num_calloc()") ... time_calloc.append(t.timeit(10000)) ... ... >>> print("mean: %.4f, std: %.4f" % (np.mean(time_malloc), np.std(time_malloc))) mean: 0.0098, std: 0.0034 >>> print("mean: %.4f, std: %.4f" % (np.mean(time_calloc), np.std(time_calloc))) mean: 0.0098, std: 0.0026 >>> print("mean: %.4f, std: %.4f" % (np.mean(time_ndarr), np.std(time_ndarr))) mean: 0.0177, std: 0.0033
内容的提问来源于stack exchange,提问作者Elkan
相关产品推荐
相关产品推荐

