用于数值计算的多处理python函数

用于数值计算的多处理python函数,python,multithreading,numpy,multiprocessing,Python,Multithreading,Numpy,Multiprocessing,希望在并行化我的python代码方面得到一些帮助,我已经用它挣扎了一段时间,并且在我尝试的任何方式中都会出现一些错误,目前运行代码大约需要2-3个小时才能完成,下面给出了代码 import numpy as np from scipy.constants import Boltzmann, elementary_charge as kb, e import multiprocessing from functools import partial Tc = 9.2 x = [] g= [] d

希望在并行化我的python代码方面得到一些帮助,我已经用它挣扎了一段时间,并且在我尝试的任何方式中都会出现一些错误,目前运行代码大约需要2-3个小时才能完成,下面给出了代码

import numpy as np
from scipy.constants import Boltzmann, elementary_charge as kb, e
import multiprocessing
from functools import partial 
Tc = 9.2
x = []
g= []
def Delta(T):
'''
Delta(T) takes a temperature as an input and calculates a
temperature dependent variable based on Tc which is defined as a
global parameter  
'''
    d0 = (pi/1.78)*kb*Tc
    D0 = d0*(np.sqrt(1-(T**2/Tc**2)))
    return D0

def element_in_sum(T, n, phi):
    D = Delta(T)
    matsubara_frequency = (np.pi * kb * T) * (2*n + 1)
    factor_d = np.sqrt((D**2 * cos(phi/2)**2) + matsubara_frequency**2)
    element = ((2 * D * np.cos(phi/2))/ factor_d) * np.arctan((D * np.sin(phi/2))/factor_d)
    return element

def sum_elements(T, M, phi):
'''
  sum_elements(T,M,phi) is the most computationally heavy part
  of the calculations, the larger the M value the more accurate the 
  results are.
  T: temperature
  M: number of steps for matrix calculation the larger the more accurate the calculation
 phi: The phase of the system can be between 0- pi 
'''
    X = list(np.arange(0,M,1))
    Y = [element_in_sum(T, n, phi) for n in X]
    return sum(Y)

def KO_1(M, T, phi):
    Iko1Rn = (2 * np.pi * kb * T /e) * sum_elements(T, M, phi)
    return Iko1Rn

def main():
    for j in range(1, 92):
        T = 0.1*j
        for i in range(1, 314):
            phi = 0.01*i
            pool = multiprocessing.Pool()
            result = pool.apply_async(KO_1,args=(26000, T, phi,))
            g.append(result)
            pool.close()
            pool.join()    
     A = max(g);
     x.append(A)
     del g[:]       

我的方法是尝试将KO1函数发送到多处理池中,但我要么遇到
酸洗
错误,要么打开的文件太多
,非常感谢任何帮助,如果多处理是错误的方法,我希望得到任何指导。

这不是问题的答案,但如果可以的话,我建议如何使用简单的numpy数组操作来加速代码。请查看以下代码:

import numpy as np
from scipy.constants import Boltzmann, elementary_charge as kb, e
import time
Tc = 9.2
RAM = 4*1024**2 # 4GB

def Delta(T):
    '''
    Delta(T) takes a temperature as an input and calculates a
    temperature dependent variable based on Tc which is defined as a
    global parameter  
    '''
    d0 = (np.pi/1.78)*kb*Tc
    D0 = d0*(np.sqrt(1-(T**2/Tc**2)))
    return D0

def element_in_sum(T, n, phi):
    D = Delta(T)
    matsubara_frequency = (np.pi * kb * T) * (2*n + 1)
    factor_d = np.sqrt((D**2 * np.cos(phi/2)**2) + matsubara_frequency**2)
    element = ((2 * D * np.cos(phi/2))/ factor_d) * np.arctan((D * np.sin(phi/2))/factor_d)
    return element


def KO_1(M, T, phi):
    X = np.arange(M)[:,np.newaxis,np.newaxis]
    sizeX = int((float(RAM) / sum(T.shape))/sum(phi.shape)/8) #8byte
    i0 = 0
    Iko1Rn = 0. * T * phi
    while (i0+sizeX) <= M:
        print "X = %i"%i0
        indices = slice(i0, i0+sizeX)
        Iko1Rn += (2 * np.pi * kb * T /e) * element_in_sum(T, X[indices], phi).sum(0)
        i0 += sizeX
    return Iko1Rn

def main():
    T = np.arange(0.1,9.2,0.1)[:,np.newaxis]
    phi = np.linspace(0,np.pi, 361)
    M = 26000
    result = KO_1(M, T, phi)
    return result, result.max()

T0 = time.time()
r, rmax = main()
print time.time() - T0
将numpy导入为np
从scipy.constants导入Boltzmann,基本电荷为kb,e
导入时间
Tc=9.2
RAM=4*1024**2#4GB
def增量(T):
'''
Delta(T)将温度作为输入并计算温度
基于Tc的温度因变量,定义为
全局参数
'''
d0=(np.pi/1.78)*kb*Tc
D0=D0*(np.sqrt(1-(T**2/Tc**2)))
返回D0
定义元素和(T,n,φ):
D=δ(T)
松原频率=(np.pi*kb*T)*(2*n+1)
因子d=np.sqrt((d**2*np.cos(phi/2)**2)+松原频率**2)
元素=((2*D*np.cos(phi/2))/factor_D)*np.arctan((D*np.sin(phi/2))/factor_D)
返回元素
def KO_1(M,T,phi):
X=np.arange(M)[,np.newaxis,np.newaxis]
sizeX=int((浮点(RAM)/sum(T形))/sum(φ形)/8)#8字节
i0=0
Iko1Rn=0。*T*phi

虽然(i0+sizeX)这不是问题的答案,但如果可以的话,我会建议如何使用简单的numpy数组操作来加速代码。请查看以下代码:

import numpy as np
from scipy.constants import Boltzmann, elementary_charge as kb, e
import time
Tc = 9.2
RAM = 4*1024**2 # 4GB

def Delta(T):
    '''
    Delta(T) takes a temperature as an input and calculates a
    temperature dependent variable based on Tc which is defined as a
    global parameter  
    '''
    d0 = (np.pi/1.78)*kb*Tc
    D0 = d0*(np.sqrt(1-(T**2/Tc**2)))
    return D0

def element_in_sum(T, n, phi):
    D = Delta(T)
    matsubara_frequency = (np.pi * kb * T) * (2*n + 1)
    factor_d = np.sqrt((D**2 * np.cos(phi/2)**2) + matsubara_frequency**2)
    element = ((2 * D * np.cos(phi/2))/ factor_d) * np.arctan((D * np.sin(phi/2))/factor_d)
    return element


def KO_1(M, T, phi):
    X = np.arange(M)[:,np.newaxis,np.newaxis]
    sizeX = int((float(RAM) / sum(T.shape))/sum(phi.shape)/8) #8byte
    i0 = 0
    Iko1Rn = 0. * T * phi
    while (i0+sizeX) <= M:
        print "X = %i"%i0
        indices = slice(i0, i0+sizeX)
        Iko1Rn += (2 * np.pi * kb * T /e) * element_in_sum(T, X[indices], phi).sum(0)
        i0 += sizeX
    return Iko1Rn

def main():
    T = np.arange(0.1,9.2,0.1)[:,np.newaxis]
    phi = np.linspace(0,np.pi, 361)
    M = 26000
    result = KO_1(M, T, phi)
    return result, result.max()

T0 = time.time()
r, rmax = main()
print time.time() - T0
将numpy导入为np
从scipy.constants导入Boltzmann,基本电荷为kb,e
导入时间
Tc=9.2
RAM=4*1024**2#4GB
def增量(T):
'''
Delta(T)将温度作为输入并计算温度
基于Tc的温度因变量,定义为
全局参数
'''
d0=(np.pi/1.78)*kb*Tc
D0=D0*(np.sqrt(1-(T**2/Tc**2)))
返回D0
定义元素和(T,n,φ):
D=δ(T)
松原频率=(np.pi*kb*T)*(2*n+1)
因子d=np.sqrt((d**2*np.cos(phi/2)**2)+松原频率**2)
元素=((2*D*np.cos(phi/2))/factor_D)*np.arctan((D*np.sin(phi/2))/factor_D)
返回元素
def KO_1(M,T,phi):
X=np.arange(M)[,np.newaxis,np.newaxis]
sizeX=int((浮点(RAM)/sum(T形))/sum(φ形)/8)#8字节
i0=0
Iko1Rn=0。*T*phi

虽然(i0+sizeX)我还没有测试您的代码,但是您可以做一些事情来改进它

首先,不要不必要地创建数组
sum_elements
仅使用一个生成器即可创建三个类似数组的对象。首先,
np.arange
创建一个numpy数组,然后
list
函数创建一个列表对象,然后列表理解创建另一个列表。该函数所做的工作是它应该做的工作的4倍

正确的实现方法(在python3中)是:

def sum_elements(T, M, phi):
    return sum(element_in_sum(T, n, phi) for n in range(0, M, 1))
如果使用python2,请将
range
替换为
xrange
。 这个技巧可能会帮助您编写任何python脚本

另外,尝试更好地利用多处理。似乎您需要做的是创建一个
多处理.Pool
对象一次,然后使用
Pool.map
函数

主要功能应如下所示:

def job(args):
   i, j = args
   T = 0.1*j
   phi = 0.01*i
   return K0_1(26000, T, phi)

def main():        
    pool = multiprocessing.Pool(processes=4) # You can change this number
    x = [max(pool.imap(job, ((i, j) for i in range(1, 314)) for j in range(1, 92)]

请注意,我使用了一个元组来向job传递多个参数。

我还没有测试您的代码,但您可以做一些事情来改进它

首先,不要不必要地创建数组
sum_elements
仅使用一个生成器即可创建三个类似数组的对象。首先,
np.arange
创建一个numpy数组,然后
list
函数创建一个列表对象,然后列表理解创建另一个列表。该函数所做的工作是它应该做的工作的4倍

正确的实现方法(在python3中)是:

def sum_elements(T, M, phi):
    return sum(element_in_sum(T, n, phi) for n in range(0, M, 1))
如果使用python2,请将
range
替换为
xrange
。 这个技巧可能会帮助您编写任何python脚本

另外,尝试更好地利用多处理。似乎您需要做的是创建一个
多处理.Pool
对象一次,然后使用
Pool.map
函数

主要功能应如下所示:

def job(args):
   i, j = args
   T = 0.1*j
   phi = 0.01*i
   return K0_1(26000, T, phi)

def main():        
    pool = multiprocessing.Pool(processes=4) # You can change this number
    x = [max(pool.imap(job, ((i, j) for i in range(1, 314)) for j in range(1, 92)]

请注意,我使用元组向job传递多个参数。

我认为您可以大大减少代码的运行时间,但使用正确的数组操作而不是for循环,因为您的操作似乎涉及相当简单的数学。(如果我错了,请纠正我)。这段代码看起来像是由C程序员编写的;)检查这些:Iol我很荣幸:D@dnalow但遗憾的是,这是一位刚开始编程的化学家转为工程师写的,我对使用Numpy的网格方面很感兴趣,但我不太确定如何在这里实现它。而不是多线程,我认为您可以大大减少代码的运行时间,但是使用正确的数组操作而不是for循环,因为您的代码似乎涉及相当简单的数学。(如果我错了,请纠正我)。这段代码看起来像是由C程序员编写的;)检查这些:Iol我很荣幸:D@dnalow但遗憾的是,这是一位刚开始编程的化学家转为工程师写的,我对使用Numpy的网格方面很感兴趣,但我不太确定如何在这里实现它。谢谢你,我喜欢这里的简单,非常感谢你给我的提示,从现在开始,当我打开代码时,虽然我一直得到
NameError:global name'K0_1'没有定义
这些代码片段是用来替换
sum_元素的