Multithreading cython.parallel:如何初始化线程本地ndarray缓冲区?
我正在努力用cython.parallel初始化线程本地Ndarray: 伪代码:Multithreading cython.parallel:如何初始化线程本地ndarray缓冲区?,multithreading,numpy,openmp,cython,Multithreading,Numpy,Openmp,Cython,我正在努力用cython.parallel初始化线程本地Ndarray: 伪代码: cdef: ndarray buffer with nogil, parallel(): buffer = np.empty(...) for i in prange(n): with gil: print "Thread %d: data address: 0x%x" % (threadid(), <uintptr_t>buffer
cdef:
ndarray buffer
with nogil, parallel():
buffer = np.empty(...)
for i in prange(n):
with gil:
print "Thread %d: data address: 0x%x" % (threadid(), <uintptr_t>buffer.data)
some_func(buffer.data) # use thread-local buffer
cdef void some_func(char * buffer_ptr) nogil:
(... works on buffer contents...)
cdef:
缓冲区
使用nogil,parallel():
buffer=np.empty(…)
对于prange中的i(n):
与gil合作:
打印“线程%d:数据地址:0x%x”%(threadid(),buffer.data)
一些_func(buffer.data)#使用线程本地缓冲区
cdef void some_func(char*buffer_ptr)nogil:
(…适用于缓冲区内容…)
我的问题是,在所有线程缓冲区中,数据指向相同的地址。即上次分配的缓冲区的线程地址
尽管在parallel()
(或者prange
)块中分配了buffer
,cython不会使buffer
成为private
或线程局部变量,而是将其作为shared
变量保留
结果,buffer.data
指向同一个内存区域,对我的算法造成了严重破坏
这不仅仅是ndarray对象的问题,似乎是所有cdef类
定义的对象的问题
如何解决这个问题?我想我终于找到了我喜欢的解决这个问题的方法。
简短的版本是创建具有以下形状的数组:
(线程数,…)
然后,调用openmp.omp_get_thread_num并使用该函数对数组进行索引,以获取“thread local”子数组。这避免了每个循环索引都有一个单独的数组(这可能是巨大的),但也防止了线程相互覆盖
以下是我所做工作的大致版本:
import numpy as np
import multiprocessing
from cython.parallel cimport parallel
from cython.parallel import prange
cimport openmp
cdef extern from "stdlib.h":
void free(void* ptr)
void* malloc(size_t size)
void* realloc(void* ptr, size_t size)
...
cdef int num_items = ...
num_threads = multiprocessing.cpu_count()
result_array = np.zeros((num_threads, num_items), dtype=DTYPE) # Make sure each thread uses separate memory
cdef c_numpy.ndarray result_cn
cdef CDTYPE ** result_pointer_arr
result_pointer_arr = <CDTYPE **> malloc(num_threads * sizeof(CDTYPE *))
for i in range(num_threads):
result_cn = result_array[i]
result_pointer_arr[i] = <CDTYPE*> result_cn.data
cdef int thread_number
for i in prange(num_items, nogil=True, chunksize=1, num_threads=num_threads, schedule='static'):
thread_number = openmp.omp_get_thread_num()
some_function(result_pointer_arr[thread_number])
将numpy导入为np
导入多处理
从cython.parallel cimport parallel
来自cython.平行进口prange
cimport openmp
来自“stdlib.h”的cdef外部:
无空隙(空隙*ptr)
void*malloc(大小)
void*realloc(void*ptr,大小)
...
cdef int num_项=。。。
num\u threads=多处理.cpu\u计数()
result_array=np.zeros((num_线程,num_项),dtype=dtype)#确保每个线程使用单独的内存
cdef c_numpy.ndarray结果\u cn
cdef CDTYPE**结果\u指针\u arr
结果\u指针\u arr=malloc(num\u threads*sizeof(CDTYPE*))
对于范围内的i(num_线程):
结果\u cn=结果\u数组[i]
结果\u指针\u arr[i]=结果\u cn.data
cdef int螺纹号
对于prange中的i(num_items,nogil=True,chunksize=1,num_threads=num_threads,schedule='static'):
thread\u number=openmp.omp\u get\u thread\u num()
某些函数(结果\u指针\u arr[线程\u编号])
你能在没有gil的情况下调用np.empty
吗?也许会带来你想要的…@BiRico这是一个反问句:)?不,您绝对不能在nogil
块中实例化numpy数组(或memoryview)(否则数组将不会在Python的托管内存中分配,也无法进行垃圾收集等)。据我所知,Cython不允许线程私有numpy数组或MemoryView(如果这种情况已经改变,那么我很想听听!)。正如Saullo所建议的,您最好的选择可能是在并行块之外分配一个大数组,然后向每个工作线程传递一个指向要使用的数组段的指针?如果您使用内存视图,它甚至不允许您编译。“Memoryview切片只能在并行分区中共享”