【问题标题】:cython shared memory in cython.parallel.prange - blockcython.parallel.prange 中的 cython 共享内存 - 块
【发布时间】:2013-09-30 21:38:06
【问题描述】:

我有一个函数foo,它接受一个指向内存的指针作为参数,并写入和读取该内存:

cdef void foo (double *data):
   data[some_index_int] = some_value_double
   do_something_dependent_on (data)

我正在分配给data,如下所示:

cdef int N = some_int
cdef double *data = <double*> malloc (N * sizeof (double))

cdef int i
for i in cython.parallel.prange (N, nogil=True):
    foo (data)

readout (data)

我现在的问题是:不同的线程如何处理这个问题?我的猜测是data 指向的内存将由所有线程共享,并在函数foo 内部“同时”读取或写入。这会弄乱所有结果,因为不能依赖先前设置的数据值(在foo 内)?我的猜测是正确的还是在 cython 编译器中实现了一些神奇的安全带?

非常感谢您。

【问题讨论】:

    标签: python parallel-processing malloc cython python-multithreading


    【解决方案1】:

    我假设没有对data 的读取或写入同步锁,线程将读取/写入内存位置并覆盖彼此的更改。如果没有某种同步,您将无法获得一致的结果。

    虽然文档 (http://docs.cython.org/src/userguide/parallelism.html) 似乎建议 OpenMP(默认后端)自动创建线程本地。

    【讨论】:

    • 注意:我的任何系统上都没有 OpenMP,因此无法轻松测试。
    【解决方案2】:

    一个好的方法是让主数组beeing 位于线程之外。然后你给每个线程一个指针,指向应该由线程计算的主数组部分。

    以下示例是矩阵乘法的实现(类似于二维数组的dot),其中:

    c = a*b
    

    这里的并行性是在a 的行上实现的。检查指针是如何传递给multiply 函数的,以允许不同的线程共享相同的数组。

    import numpy as np
    cimport numpy as np
    import cython
    from cython.parallel import prange
    
    ctypedef np.double_t cDOUBLE
    DOUBLE = np.float64
    
    
    def mydot(np.ndarray[cDOUBLE, ndim=2] a, np.ndarray[cDOUBLE, ndim=2] b):
        cdef np.ndarray[cDOUBLE, ndim=2] c
        cdef int i, M, N, K
    
        c = np.zeros((a.shape[0], b.shape[1]), dtype=DOUBLE)
        M = a.shape[0]
        N = a.shape[1]
        K = b.shape[1]
    
        for i in prange(M, nogil=True):
            multiply(&a[i,0], &b[0,0], &c[i,0], N, K)
    
        return c
    
    
    @cython.wraparound(False)
    @cython.boundscheck(False)
    @cython.nonecheck(False)
    cdef void multiply(double *a, double *b, double *c, int N, int K) nogil:
        cdef int j, k
        for j in range(N):
            for k in range(K):
                c[k] += a[j]*b[k+j*K]
    

    要检查你可以使用这个脚本:

    import time
    
    import numpy as np
    
    import _stack
    
    a = np.random.random((10000,500))
    b = np.random.random((500,2000))
    
    t = time.clock()
    c = np.dot(a, b)
    print('finished dot: {} s'.format(time.clock()-t))
    
    t = time.clock()
    c2 = _stack.mydot(a, b)
    print('finished mydot: {} s'.format(time.clock()-t))
    
    print 'Passed test:', np.allclose(c, c2)
    

    它在我的电脑上给出的位置:

    finished dot: 0.601547366526 s
    finished mydot: 2.834147917 s
    Passed test: True
    

    如果a 的行数小于列数或b 中的列数,mydot 会更糟,需要更好地检查哪个维度进行并行化。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-31
      • 1970-01-01
      • 1970-01-01
      • 2014-10-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多