2016-09-16 3 views
0

ここで私のPythonコードを並列化して助けを得たいと願っていますが、私はしばらくそれに苦労しています。完了までに2〜3時間、コードは以下の通りです。数値計算のためのマルチプロセッシングPython関数

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機能を試してみて、送信することでしたが、私はどちらかPicklingエラーまたはtoo many files open、すべてのヘルプは大歓迎されます、そしてマルチプロセッシングは間違ったアプローチであるならば、私はすべてのガイドを大好きです。

+0

マルチスレッドの代わりに、コードのランタイムを減らすことができますが、ループの代わりに適切な配列操作を使用すると、かなり単純な数学が必要になると思われます。 (私が間違っているなら私を修正してください)。このコードはCのプログラムマーによって書かれたようです) 次の項目を確認してください:http://technicaldiscovery.blogspot.de/2011/06/speeding-up-python-numpy-cython-and.html http:// scipy -cookbook.readthedocs.io/items/PerformancePython.html – dnalow

+0

Iol私は賞賛されています:D @nnnnowしかし、これはプログラミングに慣れていない化学者志向のエンジニアだった人によって書かれましたが、私は間違いなくナンシーだけど、ここでそれをどうやって実装するかについてはあまり気にしていなかった。 – user3191569

答えて

1

私はあなたのコードをテストしていませんが、改善するためにいくつかのことを行うことができます。

まず、不必要に配列を作成しないでください。 sum_elementsは、1つのジェネレータしか使用できない場合、3つの配列のようなオブジェクトを作成します。まず、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を使用している場合は、xrangerangeを交換してください。 このヒントは、あなたが書くすべてのPythonスクリプトで役に立ちます。

また、マルチプロセッシングをより有効に活用してください。あなたがする必要があるのはmultiprocessing.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)] 

注意してください。

+0

ありがとう、私はここでシンプルさを愛しています。 'NameError:グローバル名 'K0_1'が定義されていません。 – user3191569

+0

スニペットはそれぞれ' sum_elements'と 'main'を置き換えるものです。 –

+0

ええ、私は 'sum_elements'と' main'をまっすぐに置き換えましたが、 'main()'を実行したときにエラーが発生しました – user3191569

1

これは疑問の答えではありませんが、私が思うなら、簡単な配列操作を使ってコードを高速化する方法を提案します。次のコードをご覧ください。

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 

私のPCでは20秒以上実行されます。あまりにも多くのメモリを使用しないように注意しなければならないため、Xの部分だけを使用する複雑な構造のループがまだ残っています。十分なメモリがあれば、必要ありません。

これはスピードアップの最初のステップに過ぎないことにも注意してください。それでもなお、例えばちょうど時間のコンパイルやcython。

+0

私はこれが大好きです、それは質問に答えることができないかもしれませんが、これは挑戦者にとって挑戦的です。 – user3191569

+0

ここで私はデータポイント、第1次元M、第2次元T、第3次元φの立方体に及んでいることを忘れています。内部的には、最初の次元(.sum(0))を元のように合計したものです – dnalow

関連する問題