Python 似乎multiprocessing.pool接受相同的参数两次

Python 似乎multiprocessing.pool接受相同的参数两次,python,python-multiprocessing,Python,Python Multiprocessing,我正在使用multiprocessing.pool并行执行多重集成 在这个程序中,我通过生成dW3D阵列,为不同的噪声实现集成了一个运动方程。程序的第一部分只是定义参数和生成计算所需的数组 我在函数外部生成dW,因为我知道,否则我必须在每个进程中重新设定种子,以避免获得相同的随机序列 Euler(replica)函数是必须并行化的函数。这包括对数值积分的单个过程进行循环。argreplica是存储在“replicas”数组中的我的系统副本的编号,这是在pool.map中传递的参数 import

我正在使用
multiprocessing.pool
并行执行多重集成

在这个程序中,我通过生成
dW
3D阵列,为不同的噪声实现集成了一个运动方程。程序的第一部分只是定义参数和生成计算所需的数组

我在函数外部生成
dW
,因为我知道,否则我必须在每个进程中重新设定种子,以避免获得相同的随机序列

Euler(replica)
函数是必须并行化的函数。这包括对数值积分的单个过程进行
循环。arg
replica
是存储在“replicas”数组中的我的系统副本的编号,这是在
pool.map
中传递的参数

import numpy as np 
from multiprocessing import Pool

# parameters
N = 30               # number of sites
T = 1                # total time
dt = 0.1             # time step
l = 0                # initially localized state on site l
e = 0.0              # site energy
v = 1.0              # hopping coefficient
mu, sigma = 0, 1.0   # average and variance of the gaussian distribution
num_replicas = 8     # number of replicas of the system
processes=2          # number of processes

# identity vector which represents the diagonal of the Hamiltonian
E = np.ones(N) * e

# vector which represents the upper/lower diagonal terms of the Hopping Matrix and the Hamiltonian
V = np.ones(N-1) * v

# definition of the tight-binding Hamiltonian (tridiagonal)
H = np.diag(E) + np.diag(V, k=1) + np.diag(V, k=-1)

# corner elements of the Hamiltonian
H[0, -1] = v
H[-1, 0] = v

# time array
time_array = np.arange(0, T, dt)

# site array
site_array = np.arange(N)

# initial state
psi_0 = np.zeros((N), dtype=complex)
psi_0[l] = 1. + 0.j

#initialization of the state array
Psi = np.zeros((len(time_array), N), dtype=complex)
Psi[0,:] = psi_0 

# replicas 1D array
replicas = np.arange(0, num_replicas)

# random 2D array
dW = np.random.normal(mu, 1.0, (len(time_array), num_replicas, N)) * np.sqrt(dt)

def Euler(replica):
    psi_0 = np.zeros((N), dtype=complex)
    psi_0[l] = 1. + 0.j
    psi = psi_0
    for i in np.arange(1, len(time_array)):
        psi += -1.j * (H @ psi) * dt - 1.j * sigma * psi * dW[i,replica,:] - 0.5 * (sigma**2) * psi * dt
        psi /= np.sqrt(psi @ np.conj(psi))
        Psi[i,:] = psi
    return Psi

pool = Pool(processes)
Psi = pool.map(Euler, replicas)

Psi = np.asarray(Psi)

Psi = np.swapaxes(Psi,0,1)

print(Psi)

根据经验,我发现如果
num\u replicas>4个进程
pool.map
函数所示,那么两个进程似乎采用相同的参数,就好像相同的计算重复了两次。相反,从'num_副本中,我认为您应该初始化Euler函数中的psi_0和“psi”。 我试图重现您的结果,事实上,我发现当
num\u replicas>4*个进程
时,您从多个处理器获得相同的结果。但我认为这是因为Psi,在你的例子中,它是一个全局变量

按如下方式修改代码,它会为每个num_副本提供不同的结果(顺便问一下,为什么要使用site_阵列?它不在任何地方使用)


正如@Fabrizio所指出的,
Psi
Euler
的调用之间共享。这通常是一件坏事,也是为什么“全局可变状态”是个坏主意的另一个例子。事情很容易以意想不到的方式破裂

在这种情况下,它失败的原因很微妙,这是由于在酸洗它们并将它们返回到父/控制过程之前,每个过程中的方式造成的。您可以通过将
map
chunksize
参数设置为
1
来看到这一点,从而使其立即返回结果,因此不会覆盖中间结果

这相当于以下最小工作示例:

from multiprocessing import Pool

arr = [None]

def mutate_global(i):
    arr[0] = i
    return arr

with Pool(2) as pool:
    out = pool.map(mutate_global, range(10), chunksize=5)

print(out)
上次我运行此程序时,我得到:

[[4], [4], [4], [4], [4], [9], [9], [9], [9], [9]]
您可以更改
chunksize
参数来了解它在做什么,也可以使用以下版本运行:

def mutate_local(i):
    arr = [None]
    arr[0] = i
    return arr
它“只起作用”,等同于@Fabrizio所描述的在
Euler
内部创建
Phi
而不是使用单个全局变量

def mutate_local(i):
    arr = [None]
    arr[0] = i
    return arr