如何在Cython中使用Prange? [英] How to use prange in cython?

查看:165
本文介绍了如何在Cython中使用Prange?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Monte Carlo方法求解2D-Ising模型.

由于速度很慢,我使用Cython来加速代码执行.我想进一步推动它并并行化Cython代码.我的想法是将2D晶格一分为二,因此对于晶格上的任何点,它在另一个晶格上的距离​​都最近.这样,我可以随机选择一个晶格,并且可以翻转所有自旋,并且由于所有这些自旋都是独立的,因此可以并行完成此操作.

到目前为止,这是我的代码:
(灵感来自解决方案

从Cython的角度来看,主要问题是 cy_spin_flip 需要GIL.您需要在其签名的末尾添加 nogil ,并将返回类型设置为 void (因为默认情况下它返回一个Python对象,需要GIL)./p>

但是, np.exp np.random.rand 也需要GIL,因为它们是Python函数调用. np.exp 可能很容易替换为 libc.math.exp . np.random 有点难,但是对于基于C和C ++的方法有很多建议:2 3

 范围(2)中的奇数偶数:对于prange(M)中的m:对于范围(N)中的n:#在此处选择备用单元的某种机制. 

即您需要一个常规循环来选择并行循环之外的备用单元.

I'm trying to solve a 2D-Ising model with Monte Carlo approach.

As it is slow I used Cython to accelerate the code execution. I would like to push it even further and parallelize the Cython code. My idea is to split the 2D-lattice in two, so for any point on a lattice has it's nearest neigbours on the other lattice. This way I can randomly choose one lattice and I can flip all the spins and this could be done in parallel since all those spins are independent.

So far this is my code :
( inspired from
http://jakevdp.github.io/blog/2017/12/11/live-coding-cython-ising-model/ )

%load_ext Cython
%%cython 
cimport cython
cimport numpy as np
import numpy as np
from cython.parallel cimport prange

@cython.boundscheck(False)
@cython.wraparound(False)

def cy_ising_step(np.int64_t[:, :] field,float beta):

    cdef int N = field.shape[0]
    cdef int M = field.shape[1]


    cdef int offset = np.random.randint(0,2)

    cdef np.int64_t[:,] n_update = np.arange(offset,N,2,dtype=np.int64)

    cdef int m,n,i,j

    for m in prange(M,nogil=True):
        i = m % 2
        for j in range(n_update.shape[0]) :
            n = n_update[j]

            cy_spin_flip(field,(n+i) %N,m%M,beta)

    return np.array(field,dtype=np.int64)


cdef cy_spin_flip(np.int64_t[:, :] field,int n,int m, float beta=0.4,float J=1.0):

    cdef int N = field.shape[0]
    cdef int M = field.shape[1]

    cdef float dE = 2*J*field[n,m]*(field[(n-1)%N,m]+field[(n+1)%N,m]+field[n,(m-1)%M]+field[n,(m+1)%M])

    if dE <= 0 :
        field[n,m] *= -1

    elif np.exp(-dE * beta) > np.random.rand():
        field[n,m] *= -1

I tried using a prange-constructor but I'm having a lots of troubles with GIL-lock. I'am new to Cython and parallel computing so I could easily have missed something.

The error :

Discarding owned Python object not allowed without gil
Calling gil-requiring function not allowed without gil

解决方案

From a Cython point-of-view the main problem is that cy_spin_flip requires the GIL. You need to add nogil to the end of its signature, and set the return type to void (since by default it returns a Python object, which requires the GIL).

However, np.exp and np.random.rand also require the GIL, because they're Python function calls. np.exp is probably easily replaced with libc.math.exp. np.random is a bit harder, but there's plenty of suggestions for C- and C++-based approaches: 1 2 3 4 (+ others).


A more fundamental problem is the line:

cdef float dE = 2*J*field[n,m]*(field[(n-1)%N,m]+field[(n+1)%N,m]+field[n,(m-1)%M]+field[n,(m+1)%M])

You've parallelized this with respect to m (i.e. different values of m are run in different threads), and each iteration changes field. However in this line you are looking up several different values of m. This means the whole thing is a race-condition (the result depends on which order the different threads finish) and suggests your algorithm may be fundamentally unsuitable for parallelization. Or that you should copy field and have field_in and field_out. It isn't obvious to me, but this is something that you should be able to work out.

Edit: it does look like you've given the race condition some thought with using i%2. It isn't obvious to me that this is right though. I think a working implementation of your "alternate cells" scheme would look something like:

for oddeven in range(2):
    for m in prange(M):
        for n in range(N):
            # some mechanism to pick the alternate cells here.

i.e. you need a regular loop to pick the alternate cells outside your parallel loop.

这篇关于如何在Cython中使用Prange?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆