我可以在Cython中使用这个并行迭代器模式吗?

时间:2013-07-23 08:29:37

标签: python c++11 openmp cython

使用C ++ 11,我一直使用以下模式来实现具有并行迭代器的图形数据结构。节点只是索引,边缘是邻接数据结构中的条目。为了遍历所有节点,将函数(lambda,closure ...)传递给parallelForNodes方法,并以每个节点作为参数进行调用。迭代细节很好地封装在方法中。

现在我想尝试与Cython相同的概念。 Cython提供cython.parallel.prange函数,该函数使用OpenMP来并行化范围内的循环。要使并行工作,需要使用nogil=True参数停用Python的全局解释器锁。如果没有GIL,则不允许使用Python对象,这使得这很棘手。

是否可以在Cython中使用这种方法?

class Graph:

    def __init__(self, n=0):
        self.n = n
        self.m = 0  
        self.z = n  # max node id
        self.adja = [[] for i in range(self.z)]
        self.deg = [0 for i in range(self.z)]

    def forNodes(self, handle):
        for u in range(self.z):
            handle(u)

    def parallelForNodes(self, handle):
        # first attempt which will fail...
        for u in prange(self.z, nogil=True):
            handle(u)


# usage 

def initialize(u):
    nonlocal ls
    ls[u] = 1

G.parallelForNodes(initialize)

1 个答案:

答案 0 :(得分:1)

首先,没有GIL,事情不可能是Python对象。

from cython.parallel import prange

cdef class Graph:
    cdef int n, m, z

    def __cinit__(self, int n=0):
        self.z = n  # max node id

    cdef void parallelForNodes(self, void (*handle)(int) nogil) nogil:
        cdef int u
        for u in prange(self.z, nogil=True):
            handle(u)

最大的问题是我们的函数指针也是 nogil

parallelForNodes本身不一定是nogil,但没有理由不这样做。

然后我们需要一个 C 函数来调用:

cdef int[100] ls
cdef void initialize(int u) nogil:
    global ls
    ls[u] = 1

它只是有效!

Graph(100).parallelForNodes(initialize)

# Print it!
cdef int[:] ls_ = ls
print(list(ls_))