python - 我可以将这种并行迭代器模式与 Cython 一起使用吗?

标签 python c++11 openmp cython

在 C++11 中,我一直在使用以下模式来实现具有并行迭代器的图形数据结构。节点只是索引,边是邻接数据结构中的条目。为了遍历所有节点,函数(lambda、闭包...)被传递给 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)

最佳答案

首先,没有 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_))

关于python - 我可以将这种并行迭代器模式与 Cython 一起使用吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17805114/

相关文章:

c++ - 关于c++中的括号

c++ - OpenMP 临界区带来意想不到的性能提升

C++:识别对象的类型

c++ - 获取回调函数的返回类型

c - OpenMP 实现还原

python - Travis CI 和 pytest 具有多个 python 版本

python - 我如何在 Numpy 的矩阵中计算 xi^j

python - 从 Google 表格电子表格调用 python 脚本的好方法是什么?

python - Pandas 中列的多个索引