Состояние гонки? - Многопоточные результаты отличаются от однопоточных - PullRequest
0 голосов
/ 21 октября 2019

Я работаю над параллельным алгоритмом Cython, который использует функцию "prange" для распараллеливания. По сути, у меня есть представление о памяти, которое я обновляю параллельно. Я заметил, что существует состояние гонки или что-то в этом роде, поскольку значения отличаются от однопоточных результатов. Кто-нибудь есть какое-либо направление, чтобы дать мне, где искать?

Я пытался настроить аргументы "prange", но, похоже, это не решает проблему. Мое понимание C довольно ограничено, но я прочитал его, чтобы увидеть, что все переменные в цикле являются частными, как и должно быть.

mp и mpi являются представлениями памяти.

for diag in prange(minlag, profile_len, num_threads=n_jobs, nogil=True):
        c = 0
        for i in range(diag, diag + w):
            c = c + ((ts[i] - mu[diag]) * (ts[i-diag] - mu[0]))

        for offset in range(n - w - diag + 1):
            c = c + df[offset] * dg[offset + diag] + df[offset + diag] * dg[offset]
            c_cmp = c * sig[offset] * sig[offset + diag]

            # update the distance profile and profile index
            if c_cmp > mp[offset]:
                if c_cmp > 1:
                    c_cmp = 1
                mp[offset] = c_cmp
                mpi[offset] = offset + diag

            if c_cmp > mp[offset + diag]:
                if c_cmp > 1:
                    c_cmp = 1
                mp[offset + diag] = c_cmp
                mpi[offset + diag] = offset

Значения mp и mpi должны быть одинаковыми как для однопоточных, так и для многопоточных. Прямо сейчас это не так.

1 Ответ

0 голосов
/ 21 октября 2019
for offset in range(n - w - diag + 1):
      # ... some stuff ...
            mp[offset] = c_cmp
            mpi[offset] = offset + diag
      # ... some stuff ...
            mp[offset + diag] = c_cmp
            mpi[offset + diag] = offset

Назначения mp и mpi выполняются для диапазона смещений от 0 до некоторого числа (которое мы не знаем, потому что это неполный пример, но это не имеет особого значения). Это происходит в каждом потоке .

Поскольку ваш алгоритм работает как с обновленным mp в цикле, так и с использованием mp в одном и том же цикле, он не выглядит особенно параллелизуемымменя. (Возможно, вместо этого можно будет распараллелить внутренний цикл (offset), но я думаю, что это вызовет проблемы со строками ...[offset + diag].)


По существу, если вы распараллелите цикл с индексомdiag тогда единственное, что вы должны изменить в цикле:

  1. Одиночные значения как «редукционная переменная» (+-*/)

  2. Массивы, индексированные diag и только diag.

Иногда возможны другие вещи, но вы должны понять, что вы 'Вы делаете это полностью и доказали себе, что несколько потоков не записывают одни и те же данные.

...