Python - Многопроцессорное заполнение под-массивов для построения глобального массива путем объединения всех под-массивов каждого процесса - PullRequest
0 голосов
/ 13 февраля 2019

В Python2.7 мне нужно построить 2D-массив (arrayFullCross_final[u][u]), который содержит 16 блоков с размером каждого блока 100x100 элементов.Вначале я использую массив 4D (arrayFullCross), затем преобразовываю его в двумерный массив 400x400.

У меня есть первая версия (последовательная), где я использую классическую функцию python «map» и«генератор», подобный этому (buildCrossMatrix_loop - это функция, к которой я хочу применить генератор generatorCrossMatrix):

# Build all big matrix with N total blocks = dimBlock*dimBlock = 16 here
arrayFullCross = np.zeros((dimBlocks, dimBlocks, arrayCross_k.size, arrayCross_mu.size))


def buildCrossMatrix_loop(params_array):

  # rows indices
  xb = params_array[0]
  # columns indices
  yb = params_array[1]
  # Current redshift
  z = zrange[params_array[2]]

  # Loop inside block
  for ub in range(dimPoints):
    for vb in range(dimPoints):
      # Diagonal terms
      if (xb == yb):
        #arrayFullCross[u][u][w][t] = 2*P_bgs**2 * N_bgs**2
        if (xb == 0):
          N_bgs = (1+1/(n[params_array[2]]*P_obs_cross(arrayCross_k[ub], arrayCross_mu[vb] , z, 10**P_m(np.log10(arrayCross_k[ub])), 10**P_m_NW(np.log10(arrayCross_k[ub])), bias2D_array*sig_8_fid, growth_f[params_array[2]]*sig_8_fid, H_orig(z), H_orig(z), D_A_orig(z), D_A_orig(z), params_array[2], 0, 0)))

          arrayFullCross[xb][xb][ub][vb] = 2*P_obs_cross(arrayCross_k[ub], arrayCross_mu[vb] , z, 10**P_m(np.log10(arrayCross_k[ub])), 10**P_m_NW(np.log10(arrayCross_k[ub])), bias2D_array*sig_8_fid, growth_f[params_array[2]]*sig_8_fid, H_orig(z), H_orig(z), D_A_orig(z), D_A_orig(z), params_array[2], 0, 0)**2 * N_bgs**2
...
...

##### MAIN LOOP to fill, at each index i, the array "arrayFullCross" #####
while i < len(zrange):

  ...
  ...

  def generatorCrossMatrix(index):
    for igen in range(dimBlocks):
      for lgen in range(dimBlocks):
        yield igen, lgen, index


  if __name__ == '__main__':
      map(buildCrossMatrix_loop, generatorCrossMatrix(i))

  ...      
  ...

i = i+1   

i - это просто указатель в основной цикл «while».

С помощью этого последовательного метода все работает нормально, и я получаю ожидаемый большой выходной массив arrayFullCross[u][v][x][y] (я проверил значения в нем и после изменения формы на 400x400, это хорошо).

Теперь япытался делать то же самое, но с multiprocessing import Pool.Я сделал:

from multiprocessing import Pool

def buildCrossMatrix_loop(params_array):
...

while i < len(zrange):
...

if __name__ == '__main__':          
      pool = mp.Pool(16)
      pool.map(buildCrossMatrix_loop, generatorCrossMatrix(i))
      pool.terminate()

      # Reshape 4D array to 2D global array
      arrayFullCross2D_final = arrayFullCross.swapaxes(1,2).reshape(dimMatCovCross,dimMatCovCross)

      print 'arrayFullCross2D_final = ', arrayFullCross2D_final

Но когда я печатаю окончательный выходной массив 2D arrayFullCross2D_final, я систематически получаю массив, заполненный только нулевыми значениями.

arrayFullCross2D_final =  [[0. 0. 0. ... 0. 0. 0.]
[0. 0. 0. ... 0. 0. 0.]
[0. 0. 0. ... 0. 0. 0.]
 ...
[0. 0. 0. ... 0. 0. 0.]
[0. 0. 0. ... 0. 0. 0.]
[0. 0. 0. ... 0. 0. 0.]]

Возможно, мне нужно сделатьразделял массив 4D arrayFullCross между разными процессами?Как я могу это сделать?

Как каждый процесс может одновременно изменять разные части массива 4D?

Кажется, что этот глобальный массив 4D перезаписывается для каждого i индекса цикла.

ОБНОВЛЕНИЕ 1: Я забыл сказать, что я объявил полный массив следующим образом (в начале основного, т.е. вне цикла while):

# Build all big matrix with N total blocks = dimBlock*dimBlock = 16 here
arrayFullCross = np.zeros((dimBlocks, dimBlocks, arrayCross_k.size, arrayCross_mu.size))

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

manager = Manager()
arrayFullCross = manager.list()

??

ОБНОВЛЕНИЕ 2: Iхотя я нашел хорошее решение, используя ThreadPool с from multiprocessing.dummy import Pool as ThreadPool, таким образом:

pool = ThreadPool(16)
pool.map(buildCrossMatrix_loop, generatorCrossMatrix(i))
pool.close()
pool.join()

Но производительность кажется плохой: действительно, я вижу только один только процесс, запущенный с top или htop команд, это нормально?

Кажется, что время в основном тратится на блокировку глобального массива для записи в него: в этом нет необходимости, поскольку я заполняю глобальный массив на независимой подпрограмме.-arrays.

Кто-нибудь уже проверял этот солют?Ион (ThreadPool)?

Любые другие альтернативы приветствуются, С уважением

1 Ответ

0 голосов
/ 13 февраля 2019

Код, похоже, действительно правильный.Однако, когда вы запускаете его в режиме пула, у каждого работника будет своя собственная копия массивов.Затем они будут записывать обратно в копию разделяемой памяти, которую вы никогда не трогаете, поэтому таблицу заполняют 0.

Используя переменные разделяемой памяти в модуле multiprocessing, вы сможете поделиться результатами сОсновная тема.Вы можете использовать массив c-типа, но это значительно увеличит сложность вашего кода.Модули multiprocessing предоставляют python-подобные списки через подмодуль Manager.Этого должно быть достаточно, чтобы составить список arrayFullCross Manager:

from multiprocessing import Manager, Pool
manager = Manager()
arrayFullCross = manager.list()

def buildCrossMatrix_loop(params_array):
...

while i < len(zrange):
...

if __name__ == '__main__':          
      pool = mp.Pool(16)
      pool.map(buildCrossMatrix_loop, generatorCrossMatrix(i))
      pool.terminate()

      # Reshape 4D array to 2D global array
      arrayFullCross2D_final = arrayFullCross.swapaxes(1,2).reshape(dimMatCovCross,dimMatCovCross)

      print 'arrayFullCross2D_final = ', arrayFullCross2D_final

Примечательно, что использование объекта manager создает определенный уровень издержек.Если производительность вас не устраивает, попробуйте использовать тип массива из multiprocessing.

Подробнее об этих ресурсах можно узнать в многопроцессорных документах .

...