With C++11 I have been using the following pattern for implementing a graph data structure with parallel iterators. Nodes are just indices, edges are entries in an adjacency data structure. For iterating over all nodes, a function (lambda, closure...) is passed to a parallelForNodes
method and called with each node as an argument. Iteration details are nicely encapsulated in the method.
Now I would like to try the same concept with Cython. Cython provides the cython.parallel.prange
function which uses OpenMP for parallelizing a loop over a range. For parallelism to work, Python's Global Interpreter Lock needs to be deactivated with the nogil=True
parameter. Without the GIL, using Python objects is not allowed, which makes this tricky.
Is it possible to use this approach with 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)