遅い (最後のカウントで 30 ~ 60 分) コードがあり、最適化する必要があります。これは、構造エンジニアリング モデル用の Abaqus のデータ抽出スクリプトです。スクリプトの最悪の部分は、オブジェクト モデル データベースを最初にフレーム (つまり、シミュレーションの時間履歴の時間) ごとに反復し、その下にネストして各ノードごとに反復するループです。ばかげたことは、約 100k の「ノード」がありますが、約 20k の有用なノードしかないということです。しかし幸いなことに、ノードは常に同じ順序になっています。つまり、ノードの uniqueLabel を検索する必要はありません。これを別のループで 1 回実行し、最後に取得したものをフィルタリングできます。そのため、すべてを 1 つのリストにまとめてから、繰り返しのノードをすべて削除しました。しかし、コードからわかるように:
timeValues = []
peeqValues = []
for frame in frames: #760 loops
setValues = frame.fieldOutputs['@@@fieldOutputType'].getSubset
region=abaqusSet, position=ELEMENT_NODAL).values
timeValues.append(frame.frameValue)
for value in setValues: # 100k loops
peeqValues.append(value.data)
value.data
約 80k 回、不必要に呼び出しを行う必要があります。誰かが Abaqus ODB (オブジェクト データベース) オブジェクトに精通している場合、それらは Python で非常に遅くなります。怪我に侮辱を加えるために、それらは、独自のpythonバージョン(2.6.x)とパッケージを持つAbaqusの下で、単一のスレッドでのみ実行されます(たとえば、numpyは利用できますが、pandasは利用できません)。面倒かもしれないもう1つのことは、オブジェクトを位置でアドレス指定できるという事実frames[-1]
ですfor frame in frames[0:10]: # iterate first 10 elements
.
itertools の経験はありませんが、setValues にマップする nodeIDs のリスト (または True/False のリスト) を提供したいと思います。スキップする setValues の長さとパターンは、760 フレームごとに常に同じです。たぶん次のようなもの:
for frame in frames: #still 760 calls
setValues = frame.fieldOutputs['@@@fieldOutputType'].getSubset(
region=abaqusSet, position=ELEMENT_NODAL).values
timeValues.append(frame.frameValue)
# nodeSet_IDs_TF = [True, True, False, False, False, ...] same length as
# setValues
filteredSetValues = ifilter(nodeSet_IDs_TF, setValues)
for value in filteredSetValues: # only 20k calls
peeqValues.append(value.data)
他のヒントも高く評価されました。この後.append()
、ループから を削除して「ドットを回避」し、すべてを関数に入れて、それが役立つかどうかを確認したかったのです。スクリプト全体はすでに 1.5 時間未満 (6 時間から 21 時間に短縮) で実行されますが、最適化を開始すると停止する方法はありません。
メモリの考慮事項も高く評価されました。私はこれらをクラスターで実行しましたが、80 GB の RAM で一度はうまくいったと思います。スクリプトは間違いなく 160 GB で動作します。問題はリソースが割り当てられることです。
解決策を探しましたが、間違ったキーワードを使用している可能性があります。これはループでは珍しい問題ではないと確信しています。
編集1
これが私が最終的に使用したものです:
# there is no compress under 2.6.x ... so use the equivalent recipe:
from itertools import izip
def compress(data, selectors):
# compress('ABCDEF', [1,0,1,0,1,1]) --> ACEF
return (d for d, s in izip(data, selectors) if s)
def iterateOdb(frames, selectors): # minor speed up
peeqValues = []
timeValues = []
append = peeqValues.append # minor speed up
for frame in frames:
setValues = frame.fieldOutputs['@@@fieldOutputType'].getSubset(
region=abaqusSet, position=ELEMENT_NODAL).values
timeValues.append(frame.frameValue)
for value in compress(setValues, selectors): # massive speed up
append(value.data)
return peeqValues, timeValues
peeqValues, timeValues = iterateOdb(frames, selectors)
最大の改善は、compress(values, selectors)
メソッドの使用によるものです (odb 部分を含むスクリプト全体が 1:30 時間から 25 分になりappend = peeqValues.append
ましたdef iterateOdb(frames, selectors):
。
https://wiki.python.org/moin/PythonSpeed/PerformanceTipsのヒントを使用しました。
答えてくれて助けてくれてありがとう!