繰り返されるPython呼び出し速度の向上(または複雑な正規表現をsedに移植)

繰り返されるPython呼び出し速度の向上(または複雑な正規表現をsedに移植)

私は学術医学物理学者です。私の実験は多くのデータを生成しますが、実行するのに費用がかかります。私たちの大学には、IBMの技術を使用して廃棄された塩鉱山に位置するロボットテープライブラリからなるバックアップシステムがあります。スペクトル保護(というdsmc)オフサイトバックアップに使用します。塩鉱山で送れる総サイズには制限はありませんが、はい1日の転送制限は200GBです。私が知っている限り、Spectrum Protectクライアントがこの制限に準拠して転送制限に達したときに停止するようにする方法はありません。

この制限に違反すると、サーバーはノードをロックし、誰かにノードのロックを解除するように求める謝罪電子メールを送信する必要があります。帯域幅が多すぎると混乱し、約24〜48時間後にノードをロック解除しました。

データを個々のチャンクで作成し(実験当日)、毎月または週ごとに帯域幅制限よりはるかに低いという事実を処理するためにdsmc送信が発生した場合、出力を解析して終了する簡単なラッパースクリプトを作成しました。大きすぎました。

解析は、dsmc単純なPythonスクリプトを使用してbashの出力をhereドキュメントとして処理することによって行われます。

#!/bin/bash
# A silly wrapper script to halt TSM backups
#
# Usage: sudo /path/to/script /path/to/backup/location 
# 
# Requires python3 accessible as python3, and the regex / os modules. 
# Tested on MacOS and Linux 
BYTES_SENT=0;
#MAX_SIZE_TO_SEND=150 #Bytes, for testing  
MAX_SIZE_TO_SEND=$[185*(2**30)] 

args=("$@")
sudo rm -f /tmp/dsmc-script.PID

function outputParser() { 
    python3 <<'EOF'
import os, re
rex=re.compile(r"Normal File\-\-\>\s*?([,0-9]*,?)\s*?\/")
valueToParse=os.environ.get('line');
match=rex.match(valueToParse);
try:
    stringToReturn = str(match.group(1));
    stringToReturn =stringToReturn.replace(',','');
except AttributeError:
    stringToReturn = "";
#Check for failed transfers 
failedResults = re.findall(r"\*\* Unsuccessful \*\*", valueToParse); 
nFailedResults = len(failedResults); 
if (nFailedResults >0):
    stringToReturn = ""; 
print(stringToReturn);
EOF
} #I am sure that the above is a one-liner in sed or awk. I just don't know what the one line is. 

function trapCaught() { 
    #Do cleanup, not shown     
    echo ", quitting."
}

trap trapCaught sigint
killCount=0 
startTime=$SECONDS

while read -r line; do  
    echo "$line"
    export line; 
    X=$(export line=$line; outputParser)
    if [[ ! -z "$X" ]]; then
        BYTES_SENT=$[$BYTES_SENT + $X]
        echo "Sent $X bytes, $BYTES_SENT in total"
    fi
    if (( BYTES_SENT > MAX_SIZE_TO_SEND )); then
        if (( killCount < 1)); then 
            echo "STOPPED BACKUP BECAUSE $BYTES_SENT is GREATER THAN THE PERMITTED MAXIMUM OF $MAX_SIZE_TO_SEND"; 
            killStartTime=$(( SECONDS - startTime ))
            pid=$(cat /tmp/dsmc-script.PID)
            echo "PID is $pid"
            echo $pid | sudo xargs kill 
        fi 

        killCount=$[$killCount + 1]; 
        timeKillNow=$(( SECONDS - killStartTime ))
        rm -f /tmp/dsmc-script.PID

        if (( killCount > 100 || timeKillNow > 30  )); then 
            echo "Taking too long to die; retrying" 
            echo $pid | sudo xargs kill -9;
            sleep 0.1; 
            sudo kill -9 0; 
        fi

    fi
done < <( sudo dsmc incr ${args[0]} &  echo $! > /tmp/dsmc-script.PID  ) 

これは動作し、私の目的に適しています。しかし、パフォーマンスは不都合で恐ろしいほどです。これは、ループを繰り返すたびにwhilePythonインタプリタ/スクリプトの組み合わせの他のインスタンスが作成されるためと想定されます。

バイナリコンパイルされたブロブの制限や動作を変更できないことを考慮すると、3つの関連するdsmc質問があります。

(a)これがこの問題を解決する合理的な方法ですか、それとも高度な魔法のように私が見逃しているより簡単な方法はありますかnetstat

(b) 与えられた Python実はそうです。ループのすべての反復で本質的に同じインタプリタのコード翻訳をキャッシュすることで、全体のプロセス速度を大幅に向上させる方法はありますか?

sed(c)Pythonスクリプトを同等のOR構成に置き換えると、awk全体の作業がはるかに高速になると思います。なぜ?このタイプの算術を簡単に実行できますか?それとも別の問題ですか?

編集する:おなじみの方のために、サンプル出力は次のdsmcようになります。文字列に「一般ファイル」が表示され、その後に対応するサイズ(バイト)が続く場合にのみファイルが送信されます。したがって、以下ではファイルがspclicert.kdb転送されますが、TSM.PWDディレクトリも転送されませんCaptiveNetworkSupport

# dsmc incr / 
< header message containing personal information> 
Incremental backup of volume '/'
ANS1898I ***** Processed    79,000 files *****
Directory-->                   0 /Library/Preferences/SystemConfiguration/CaptiveNetworkSupport [Sent]
Normal File-->             5,080 /Library/Preferences/Tivoli Storage Manager/Nodes/SHUG2765-MACBOOKPRO-PHYSICS/spclicert.kdb [Sent]
Updating-->                  224 /Library/Preferences/Tivoli Storage Manager/BrokenOrOld/TSM.PWD (original) [Sent]

したがって、上記のスクリプトは転送された各ファイルのサイズ(バイト単位)を削除し、単純に合計します。

答え1

接続が安定していると仮定すると、簡単な解決策はユーザー空間トラフィックシェーパーを使用することです。 1日の最大帯域幅以上を無効にするだけです。

使用例trickle、大容量ファイル金持ちscp:

l=$(( (200*10**6)/(24*60**2) ))
trickle -d $l    scp foo username@remotehost:~/

trickle転送速度が遅くなります2314K1秒あたりの最大速度は次を超えません。199,929,600,000毎日のバイトです。ファイル転送プログラムは必ずしも必要ではありませんscp。何でも(Webブラウザも可能)、(またはdsmc)コマンドラインから実行できます。

この方法の利点は、ファイルを分割する必要がないことです。金持ち1日の上限を超える場合。もちろん過ごすのに時間がかかるでしょう。金持ち終わり、(もし金持ち1TBなら5日かかりますが、どうせそれほど長くかかるでしょう。

trickletrickled"trickle"の各後続の実行を制御するtrickleというデーモンバージョンがあります。例:

l=$(( (200*10**6)/(24*60**2) ))
trickled -d $l
trickle    scp foo username@remotehost:~/ &
trickle    scp bar username@remotehost:~/ &
trickle    scp baz username@remotehost:~/ &

各ファイル金持ちバーブザー音はい1TBスケールの面では、trickledまだ以前のレベルを維持しています。200GB/日制限。

答え2

あなたの入力は完全にすることができますbash。例は次のとおりです。

max=$[185*(2**30)]

export total=0
while read first second third rest; do
    [[ "$first" == "Normal" && "$second" == "File-->" ]] && {
        size=${third//,/}
        echo "file: $size"
        total=$(( total + size ))
        (( total > max )) && kill something
    }
done < ~/tmp/your-input

子プロセスを作成するのにかかる時間が実際に制限されている場合、awkまたはsed

関連情報