Область действия переменной Python - PullRequest
0 голосов
/ 23 февраля 2020

У меня есть функция, оптимизированная из python, которую я пытаюсь распараллелить, используя prange. Локальные переменные определяются и инициализируются в верхней части функции, за которой следует prange, управляющий локальными переменными. Однако я получаю ошибки компилятора, говорящие, что инициализированным переменным не присваивается никакого значения. Если я переключаю prange на стандартный диапазон, все компилируется и работает нормально.

Рассматриваемая функция (взята из файла большего размера):

#cython: language_level=3
cimport cython
from cython.view cimport array as cvarray
from cython.parallel import prange
from libc.math cimport fabs

@cython.wraparound(False)
@cython.boundscheck(False)
@cython.cdivision(True)
cdef double curveanalysis(double[:] curve, double[:] outlier):
     cdef double cursign
     cdef double newsign
     cdef int c
     cdef double curmax
     cdef double curoutlier
     cdef double quality
     cdef double curstart
     cdef int curvelen
     cursign = 1.0
     newsign = 1.0
     if curve[0] !=0:
         cursign = curve[0]/fabs(curve[0])
     quality = 0
     curmax = 0.0
     curoutlier = 0
     curstart = 0.0
     curvelen = len(curve)
     for c in prange(curvelen,nogil = True):
          curoutlier += outlier[c]
          if curve[c] == 0:
               newsign = cursign
          else:
               newsign = curve[c]/fabs(curve[c])
          if newsign != cursign:
               quality += curmax*curoutlier/(c-curstart)
               cursign = newsign
               curoutlier = 0
               curmax = fabs(curve[c])
               curstart = c
          elif fabs(curve[c]) >= curmax:
               curmax = fabs(curve[c])
     return quality

Когда я пытаюсь скомпилировать программу, Я получаю четыре сообщения об ошибке, что некоторые локальные переменные не назначены:

Error compiling Cython file:
------------------------------------------------------------
...
curstart = 0.0
curvelen = len(curve)
for c in prange(curvelen,nogil = True):
    curoutlier += outlier[c]
    if curve[c] == 0:
        newsign = cursign
                 ^
------------------------------------------------------------

mastercurveprocessing.pyx:46:22: local variable 'cursign' referenced before assignment

Это происходит также для curmax и curstart. Некоторые переменные, такие как качество и курс, не дают дополнительных ошибок компилятора. Я не видел этого раньше при использовании prange, меняет ли prange область назначенных переменных? Что мне не хватает? Как сказано выше, когда я переключаю prange на диапазон, все работает нормально (хотя и не параллельно).

Я использую Cython версии 0.29.15

1 Ответ

1 голос
/ 23 февраля 2020

Проблема заключается в том, что вы присваиваете эти переменные в теле l oop, и они становятся lastprivate. Следующая выдержка из документации по Cython сообщает, какая переменная получает какой класс атрибутов совместного использования данных OpenMP:

Если вы присваиваете переменную в блоке prange, она становится lastprivate, что означает, что переменная будет содержать значение из последней итерации. Если вы используете оператор inplace для переменной, это становится уменьшением, что означает, что значения из локальных в потоке копий переменной будут уменьшены с оператором и присваивается исходной переменной после l oop. Переменная index всегда lastprivate. Переменные, назначенные параллельно с блоком, будут частными и непригодными для использования после блока, поскольку отсутствует концепция последовательного последнего значения.

Переменные Lastprivate - это локальные частные копии их оригинальных аналогов вне параллели. l oop, где оригиналу присваивается значение копии из потока, который выполнил последнюю логическую итерацию l oop. Они не имеют начальных значений, в отличие от переменных firstprivate, которые инициализируются значением исходной переменной, поэтому вы получаете ошибки.

Поскольку у вас нет контроля над выводом классов совместного использования данных, вам нужно как-то переписать код. На самом деле вашу проблему трудно распараллелить, поскольку каждая итерация зависит от предыдущей, что означает, что они должны выполняться в строгом последовательном порядке, что несовместимо с выполнением их как независимых итерационных блоков параллельно.

...