我正在尝试让 Cython 的 parallel
包的 prange
函数工作,但似乎没有有效的并行性。为了拥有 MWE,我从书中获取了示例代码 Cython: A Guide for Python Programmers并通过添加一些打印语句对其进行了一些修改。示例代码可在 github 免费获得。我指的代码位于:examples/12-parallel-cython/02-prange-parallel-loops/。
以下是我对julia.pyx文件的修改。
# distutils: extra_compile_args = -fopenmp
# distutils: extra_link_args = -fopenmp
from cython cimport boundscheck, wraparound
from cython cimport parallel
import numpy as np
cdef inline double norm2(double complex z) nogil:
return z.real * z.real + z.imag * z.imag
cdef int escape(double complex z,
double complex c,
double z_max,
int n_max) nogil:
cdef:
int i = 0
double z_max2 = z_max * z_max
while norm2(z) < z_max2 and i < n_max:
z = z * z + c
i += 1
return i
@boundscheck(False)
@wraparound(False)
def calc_julia(int resolution, double complex c,
double bound=1.5, double z_max=4.0, int n_max=1000):
cdef:
double step = 2.0 * bound / resolution
int i, j
double complex z
double real, imag
int[:, ::1] counts
counts = np.zeros((resolution+1, resolution+1), dtype=np.int32)
for i in parallel.prange(resolution + 1, nogil=True,
schedule='static', chunksize=1):
real = -bound + i * step
for j in range(resolution + 1):
imag = -bound + j * step
z = real + imag * 1j
counts[i,j] = escape(z, c, z_max, n_max)
return np.asarray(counts)
@boundscheck(False)
@wraparound(False)
def julia_fraction(int[:,::1] counts, int maxval=1000):
cdef:
unsigned int thread_id
int total = 0
int i, j, N, M
N = counts.shape[0]; M = counts.shape[1]
print("N = %d" % N)
with nogil:
for i in parallel.prange(N, schedule="static", chunksize=10):
thread_id = parallel.threadid()
with gil:
print("Thread %d." % (thread_id))
for j in range(M):
if counts[i,j] == maxval:
total += 1
return total / float(counts.size)
当我使用由
给出的setup_julia.py
编译时
from distutils.core import setup
from Cython.Build import cythonize
from distutils.extension import Extension
setup(name="julia",
ext_modules=cythonize(Extension('julia', ['julia.pyx'], extra_compile_args=['-fopenmp'], extra_link_args=['-fopenmp'])))
使用命令
python setup_julia.py build_ext --inplace
并运行 run_julia.py 文件,我看到 for 循环的所有实例只使用一个线程 -- Thread 0
。终端输出如下所示。
poulin8:02-prange-parallel-loops poulingroup$ python run_julia.py
time: 0.892143
julia fraction: N = 1001
Thread 0.
Thread 0.
Thread 0.
Thread 0.
.
.
.
.
Thread 0.
0.236994773458
据我了解,for 循环只是并行运行。有人可以指导我启动 for 循环以在多个线程之间分配负载时必须做什么吗?
我还尝试将系统变量 OMP_NUM_THREADS
设置为大于 1 的某个数字,但没有任何效果。
我在 OSX 10.11.6 上使用 Python 2.7.10 和 gcc 5.2.0 运行测试。
最佳答案
我在 Windows 7 上遇到了同样的问题。 它正在运行串行。 注意到编译信息:
python setup_julia.py build_ext --inplace
cl : Command line warning D9002 : ignoring unknown option '-fopenmp'
显然在 Visual Studio 中它必须是 -openmp
# distutils: extra_compile_args = -openmp
# distutils: extra_link_args = -openmp
现在并行运行。
如@danny 所述,您可以使用 fprintf:
from cython.parallel cimport prange, threadid
from libc.stdio cimport stdout, fprintf
def julia_fraction(int[:,::1] counts, int maxval=1000):
...
thread_id = threadid()
fprintf(stdout, "%d\n", <int>thread_id)
...
关于multithreading - 使用 Cython 启用并行性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46977293/