Python-子数组的多处理填充,通过合并每个进程的所有子数组来构建全局数组

时间:2019-02-13 14:20:32

标签: python numpy python-multiprocessing

在Python2.7中,我必须构建一个二维数组(arrayFullCross_final[u][u]),其中包含16个块,每个块的大小为100x100元素。首先,我使用4D数组(arrayFullCross),然后将其重塑为400x400 2D数组。

我有一个第一个版本(顺序版本),其中我正在使用经典的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数组的不同部分?

似乎循环的每个i索引都覆盖了这个4D全局数组。

更新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:虽然我通过将ThreadPoolfrom multiprocessing.dummy import Pool as ThreadPool结合使用以这种方式找到了一个好的解决方案:

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

但是性能似乎很差:确实,我只看到一个用tophtop命令运行的进程,这很正常吗?

似乎大部分时间都是通过锁定全局数组来写的:这是没有必要的,因为我将全局数组填充在独立的子数组上。

有人已经测试过此解决方案(ThreadPool)吗?

欢迎您使用其他任何替代方法

1 个答案:

答案 0 :(得分:0)

代码似乎确实是正确的。但是,当您在池模式下运行它时,每个工作线程将拥有自己的阵列副本。然后,它们将写回到您从未接触过的共享内存副本,因此表中填充了0。

通过使用multiprocessing模块中的共享内存变量,您应该能够与主线程共享结果。您可以使用c型数组,但这会大大增加代码的复杂性。 multiprocessing模块通过Manager子模块提供类似python的列表。将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中的Array类型。

有关这些资源的更多信息,请参见multiprocessing docs