반복되는 Python 호출 속도 향상(또는 복잡한 정규식을 sed로 포팅)

반복되는 Python 호출 속도 향상(또는 복잡한 정규식을 sed로 포팅)

저는 학술 의학 물리학자입니다. 제가 하는 실험은 많은 데이터를 생성하지만 실행하는 데 비용이 많이 듭니다. 우리 대학에는 IBM의 기술을 사용하여 버려진 소금 광산에 위치한 로봇 테이프 라이브러리로 구성된 백업 시스템이 있습니다.스펙트럼 보호(라고 함 dsmc) 오프사이트 백업에 사용합니다. 소금광산으로 보낼 수 있는 총 크기에는 제한이 없지만,하루 전송 한도는 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 인터프리터/스크립트 조합의 다른 인스턴스가 생성되기 때문이라고 가정합니다.

바이너리 컴파일된 blob의 제한이나 동작을 변경할 수 없다는 점을 고려하면 dsmc세 가지 관련 질문이 있습니다.

(a) 이것이 이 문제를 해결하는 합리적인 방법입니까, 아니면 고급 마법처럼 제가 놓치고 있는 더 쉬운 방법이 있습니까 netstat?

(b) 주어진 파이썬사실 그렇죠루프의 모든 반복에서 본질적으로 동일한 인터프리터의 코드 번역을 캐시하여 전체 프로세스 속도를 크게 높일 수 있는 방법이 있습니까?

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

연결이 안정적이라고 가정하면 간단한 해결책은 사용자 공간 트래픽 셰이퍼를 사용하는 것입니다. 하루 최대 대역폭 이상을 사용하지 않도록 설정하면 됩니다.

사용 예trickle, 대용량 파일부자, 그리고scp:

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

trickle전송 속도가 느려 집니다2314K초당 최대 속도는 다음을 초과하지 않습니다.199,929,600,000일일 바이트입니다. 파일 전송 프로그램은 반드시 일 필요는 없습니다 scp. 무엇이든(웹 브라우저도 가능), (또는 dsmc) 명령줄에서 실행될 수 있습니다.

이 방법의 장점은 파일을 분할할 필요가 없다는 것입니다.부자일일 한도를 초과하는 경우. 물론 보내는 데 시간이 좀 걸릴 것입니다.부자끝, (만약부자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.

관련 정보