2

C++11 では、並列反復子を使用してグラフ データ構造を実装するために、次のパターンを使用しています。ノードは単なるインデックスであり、エッジは隣接データ構造のエントリです。すべてのノードを反復するために、関数 (ラムダ、クロージャーなど) がメソッドに渡され、parallelForNodes各ノードを引数として呼び出されます。反復の詳細は、メソッドにうまくカプセル化されています。

次に、Cython で同じコンセプトを試してみたいと思います。Cython はcython.parallel.prangeOpenMP を使用して、範囲を超えたループを並列化する機能を提供します。並列処理を機能させるには、Python のグローバル インタープリター ロックをパラメーターで無効にする必要がありnogil=Trueます。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)
4

1 に答える 1

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_))
于 2014-01-15T10:34:30.450 に答える