0

遅い (最後のカウントで 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のヒントを使用しました。

答えてくれて助けてくれてありがとう!

4

2 に答える 2