Cython中是否有类似reinterpret_cast的机制?实现无类型内存视图快速强转
Cython中numpy结构化数组的高效内存视图复用与类型重解释方案
一、先解决核心性能问题:避免重复创建内存视图
你的代码性能差的根本原因是每次循环都重复将numpy数组转换为内存视图,这一步涉及类型检查、内存布局验证等开销,100万次重复会导致严重性能损耗。只需要把内存视图的创建移到循环外,就能直接解决性能问题:
%%cython -a cimport numpy as cnp import numpy as np from time import time cdef packed struct Bar: cnp.int64_t dt double open double high double low double close cnp.int64_t volume bar_dtype = np.dtype([('dt', 'i8'), ('open', 'f8'), ('high', 'f8'), ('low', 'f8'), ('close', 'f8'), ('volume', 'i8')]) cpdef f(Bar bar): cdef cnp.ndarray bars_sar cdef Bar[:] buffer bars_sar = np.empty((1000000,), dtype=bar_dtype) buffer = bars_sar # 仅转换一次内存视图,移至循环外 start = time() for n in range(1000000): buffer[0] = bar # 循环内直接复用已创建的内存视图 print(f'Elapsed: {time() - start}') return buffer def test(): sar = f(Bar(1,2,3,4,5,6)) print(sar[0]) return sar
修改后循环耗时会降至毫秒级,完全解决性能问题。
二、实现类似C语言reinterpret_cast的类型重解释
如果确实需要将内存以无类型形式存储,之后再重新解释为特定类型的内存视图,Cython提供两种可行方案:
方案1:通过numpy数组的底层指针实现类型重解释
直接获取numpy数组的data指针(无类型void*),需要访问时再强制转换为目标类型的内存视图:
cpdef f_reinterpret(Bar bar): cdef cnp.ndarray bars_sar cdef void* raw_ptr cdef Bar[:] buffer bars_sar = np.empty((1000000,), dtype=bar_dtype) raw_ptr = <void*>bars_sar.data # 存储无类型指针 # 需要访问时,将无类型指针转换为Bar类型的内存视图 buffer = <Bar[:bars_sar.shape[0]]>raw_ptr start = time() for n in range(1000000): buffer[0] = bar print(f'Elapsed (reinterpret): {time() - start}') return buffer
方案2:直接用C指针操作(更接近C的reinterpret_cast)
如果追求极致性能,可以直接用C指针进行内存操作,跳过内存视图的封装:
cpdef f_raw_ptr(Bar bar): cdef cnp.ndarray bars_sar cdef Bar* bar_ptr bars_sar = np.empty((1000000,), dtype=bar_dtype) bar_ptr = <Bar*>bars_sar.data # 直接转换为Bar类型指针 start = time() for n in range(1000000): bar_ptr[0] = bar # 直接通过指针访问内存 print(f'Elapsed (raw ptr): {time() - start}') # 可选:转换回内存视图返回 return <Bar[:bars_sar.shape[0]]>bar_ptr
三、关于你尝试的错误说明
你之前直接转换内存视图到void*失败,是因为内存视图(Bar[:])是Cython的封装类型,不是原始指针,不能直接转换或取地址。正确的做法是从numpy数组或内存视图的data属性获取底层原始指针,再进行类型转换。
内容的提问来源于stack exchange,提问作者viscacha
相关产品推荐
相关产品推荐

