2017-02-09 2 views
0

Я перебор с помощью Прейнджа по списку, как это:Cython parallel prange - местность резьбы?

from cython.parallel import prange, threadid 

cdef int tid 
cdef CythonElement tEl 
cdef int a, b, c 

# elList: python list of CythonElement instances is passed via function call 
for n in prange(nElements, schedule='dynamic', nogil=True): 
    with gil: 
     tEl = elList[n] 
     tid = threadid() 
     a = tEl.a 
     b = tEl.b 
     c = tEl.c 

     print("thread {:} elnumber {:}".format(tid, tEl.elNumber)) 

    #nothing is done here 

    with gil: 
     print("thread {:} elnumber {:}".format(tid, tEl.elNumber)) 

    # some other computations based on a, b and c here ... 

я ожидаю выход, как это:

thread 0 elnumber 1 
thread 1 elnumber 2 
thread 2 elnumber 3 
thread 3 elnumber 4 
thread 0 elnumber 1 
thread 1 elnumber 2 
thread 2 elnumber 3 
thread 3 elnumber 4 

Но я получаю:

thread 1 elnumber 1 
thread 0 elnumber 3 
thread 3 elnumber 2 
thread 2 elnumber 4 
thread 3 elnumber 4 
thread 1 elnumber 2 
thread 0 elnumber 4 
thread 2 elnumber 4 

Итак, как-то нить Локальная переменная tE1 будет перезаписана в потоках? Что я делаю не так ? Спасибо!

+0

Вы правы. Кажется, он не создает поток 'tEl' thread-local (посмотрите на сгенерированный файл C и найдите' lastprivate' для проверки). Если вы измените его на базовый тип (например, 'double'), он работает, но не кажется с типом объектов Cython. Я не знаю очевидного решения, но, возможно, стоит записать ошибку github – DavidW

ответ

2

Похоже, Cython намеренно исключает любые переменные Python (включая Cython cdef class es) из списка локальных переменных потока. Code

Я подозреваю, что это преднамеренно, чтобы избежать проблем с подсчетом ссылок - им нужно было бы сбросить количество ссылок на все локальные переменные потока в конце цикла (это не было бы непреодолимой проблемой, но могло бы быть большим изменением). Поэтому я думаю, что это вряд ли будет исправлено, но может оказаться полезным обновление документации.

Решение заключается в refactorise вашего тела цикла в функцию, где каждый переменные заканчивается эффективно «локальным» в функцию, так что это не проблема:

cdef f(CythonElement tEl): 
    cdef int tid 
    with nogil: 
     tid = threadid() 
     with gil: 
      print("thread {:} elnumber {:}".format(tid, tEl.elNumber)) 

     with gil: 
      print("thread {:} elnumber {:}".format(tid, tEl.elNumber)) 

    # I've trimmed the function a bit for the sake of being testable 

# then for the loop: 
for n in prange(nElements, schedule='dynamic', nogil=True): 
    with gil: 
     f() 
+0

Хорошо, я понимаю. К сожалению, похоже, что параллельный вызов cdef-расширений просто невозможно. Рефакторинг для чистых вызовов функций cdef в настоящий момент нереальна. В вашем примере f() объявляется без флага nogil, и, таким образом, не выполняется параллельно? – macmallow

+0

Он нуждается в gil в начале и в конце, если вызов refcount tEl.Он может выпустить gil внутри, и этот бит будет работать параллельно. Это должно быть не хуже кода в вашем вопросе (очевидно, в этом примере игрушек почти нет работы «gil-free»). – DavidW

0

Cython обеспечивает параллельность на основе потоков. Порядок, в котором выполняются потоки, не гарантируется, следовательно, неупорядоченные значения для thread.

Если вы хотите, чтобы tEl был закрыт для обсуждения, вы не должны определять его глобально. Попробуйте переместить cdef CythonElement tEl в пределах prange. см. http://cython-devel.python.narkive.com/atEB3yrQ/openmp-thread-private-variable-not-recognized-bug-report-discussion (часть о частных переменных).

+0

Спасибо за быстрый ответ. Тем не менее, компиляция дает мне: >>> Операция cdef здесь не разрешена <<< (Эта проблема также упоминается в опубликованной ссылке?) – macmallow

+0

Хорошо, у меня было несколько вкладок открытыми, я не могу найти место, где я видел, как cdef двигался. Повторяя ваш пример, я не вижу функции. Как правило, файлы cython скомпилируются в модули, и вызываемые функции вызываются. Является ли код над полным файлом? –

+0

Это было в ссылке на самом деле. Поиск "cdef w = Рабочий (n) # с блочным кодом cdef" –

Смежные вопросы