Чтобы сделать вещи более общими, возьмите, например, gsl_integration_qag
(так как для управления интервалами требуется рабочее пространство).Как использовать интеграцию gsl в блоке prange cython?
Вот преднамеренно простой пример (problem.pyx
):
from libc.math cimport cos
from cython.parallel import prange
from cython_gsl cimport *
cdef double mean(double[:] arr):
cdef Py_ssize_t i
cdef double sum_ = 0.0
for i in range(arr.shape[0]):
sum_ += arr[i]
return sum_/arr.shape[0]
cdef double integrand(double x, void *params) nogil:
cdef double a = (<double*>params)[0]
cdef double b = (<double*>params)[1]
return a*x + b
def use_gsl_integration_sequential():
cdef double result, error
cdef Py_ssize_t i, j
cdef double result_sum=0.0
cdef double results[3]
cdef double a=0.0, b=0.0
cdef double da = 0.1
cdef size_t space_size = 1000
cdef gsl_function gsl_func
cdef double params[2]
gsl_func.function = &integrand
cdef gsl_integration_workspace *ws
ws= gsl_integration_workspace_alloc(space_size)
for i in range(3):
a += da
result_sum = 0.0 # reset the sum(thank J.J.Hakala for pointing out this)
for j in range(4): # here may be range(100000) in practice!
b = a + j
params[0] = a; params[1] = b
gsl_func.params = params
gsl_integration_qag(&gsl_func, 0.0, 1.0, 1e-8, 1e-8, space_size, GSL_INTEG_GAUSS15, ws, &result, &error)
result_sum += result
results[i] = result_sum
gsl_integration_workspace_free(ws)
# do some other stuff with the 'results', for example:
return mean(results)
# Now, I want to parallel the inner loop
def use_gsl_integration_parallel():
cdef double result, error
cdef Py_ssize_t i, j
cdef double result_sum=0.0
cdef double results[3]
cdef double a, b
cdef double da = 0.1
cdef size_t space_size = 1000
cdef gsl_function gsl_func
cdef double params[2]
gsl_func.function = &integrand
cdef gsl_integration_workspace *ws
ws= gsl_integration_workspace_alloc(space_size)
for i in range(3):
# a should be read-only in the follow prange block.
a += da
# here may be prange(100000,...) in practice!
for j in prange(4, nogil=True):
# b should be local private.
b = a + j
# params also should be local private
params[0] = a; params[1] = b
# gsl_func is shared, only its params differ.
# According to the gsl manual(see follow link), workspaces should be allocated on a per-thread basis, but how?
gsl_func.params = params
gsl_integration_qag(&gsl_func, 0.0, 1.0, 1e-8, 1e-8, space_size, GSL_INTEG_GAUSS15, ws, &result, &error)
result_sum += result
results[i] = result_sum
gsl_integration_workspace_free(ws)
return mean(results)
Немного длинный код, только для полностью (для копирования), но я думаю, что довольно просто (читать) (1 • ᴗ • 1)
Затем компилировать & ссылка:
cython -a -2 problem.pyx
gcc -O3 -fopenmp -c problem.c -o problem.o -IC:\gsl2.1x86\include -IC:\python-2.7.10\include
gcc -shared -fPIC -fopenmp -o problem.pyd -LC:\gsl2.1x86\libs -LC:\python-2.7.10\libs problem.o -l:libgsl.a -l:libgslcblas.dll.a -l:libpython27.dll.a
В IPython:
In [1]: from problem import *
In [2]: use_gsl_integration_sequential()
Out[2]: 7.2
Результат use_gsl_integration_parallel()
не определен, я пробовал несколько раз, в лучшем случае, он сбой, с некоторым удачливым, получил неопределенное значение, поэтому должно быть что-то не так! Я просто не могу найти такой параллельный пример. Кто-нибудь мне поможет?
Окружающая среда:
win10-64bit, gcc (tdm-1) 5.1.0 32bit, python-2.7.10 32bit, cython0.24, gsl-2.1
Некоторые полезные ссылки ?:
https://github.com/twiecki/CythonGSL
https://www.gnu.org/software/gsl/manual/html_node/Thread_002dsafety.html#Thread_002dsafety
(извините, не можете больше информации, две ссылки мой предел. ..
Я думаю, что 'gsl_func' также должен быть локальным. Я также не на 100% уверен, что он будет обрабатывать «результат» как локальный здесь (я не знаю, что это не так!) – DavidW
Действительно, что меня смутило, так это то, где «распределять» эти вещи (gsl_function, params, рабочее пространство). На первый взгляд, это кажется легким - легко параллельным, но я ошибаюсь. Кроме того, поддержка cython [omp cython] (https://github.com/cython/cython/wiki/enhancements-prange#simple-usecases) довольно слабая и неявная (нарушает «Явный лучше, чем неявный»). Я начинаю сомневаться, возможен ли вопрос в цитоне. На самом деле, любой пример кода C мог бы помочь (хотя, я не знаю, как использовать omp в C.) – oz1
Я думаю, вы используете параллельный блок, выделите его там. Затем используйте prange внутри параллельного блока. Я не могу проверить это сейчас, хотя я не могу обещать, что это правильно. – DavidW