Параллелизация с Cython memoryviews


Вот минимальный пример того, что я пытаюсь сделать. Я вычисляю попарные расстояния между матрицами, которые я расположил в сложенный массив. Массив idx содержит смещения каждой подматрицы.

Когда я удаляю parallel() и заменяю prange на range, код работает так, как ожидалось (только не параллельно, конечно).

import numpy as np
cimport numpy as np
cimport cython
from cython.parallel import parallel, prange

@cython.boundscheck(False)
@cython.wraparound(False)
@cython.nonecheck(False)
def all_pairs_distance(float[:,::1] stacked, int[::1] idx):
  cdef int n = idx.shape[0] - 1
  cdef float[:,::1] D = np.zeros((n,n), dtype='float32')
  cdef int i,j
  cdef float[:,::1] t1,t2
  cdef float d
  with nogil, parallel():
    for i in prange(n):
      t1 = stacked[idx[i]:idx[i+1],:]
      for j in range(i+1, n):
        t2 = stacked[idx[j]:idx[j+1],:]
        d = nogil_cython_function(t1, t2)
        D[i,j] = d
        D[j,i] = d
  return D

cdef float nogil_cython_function(float[:,::1] a, float[:,::1] b) nogil:
  # Function abbreviated for simplicity
  return 0.0

При попытке скомпилировать этот файл, я получаю ошибки на каждом присвоении t1 или t2:

Memoryview slices can only be shared in parallel sections
  1. я не знаю, как решить эту проблему. ошибка. Разве эти задания не находятся в параллельном разделе?
  2. как сообщить компилятору, что мой stacked memoryview доступен только для чтения и может использоваться совместно между потоками?
1 3

1 ответ:

Я понял это, немного поэкспериментировав:

for i in prange(n, nogil=True):
  for j in range(i+1, n):
    d = nogil_cython_function(stacked[idx[i]:idx[i+1],:],
                              stacked[idx[j]:idx[j+1],:])

Вывод состоит в том, что нарезка memoryviews внутри prange хороша, но назначение этих срезов переменным-нет.