다음 코드의 성능을 향상시키는 방법

다음 코드의 성능을 향상시키는 방법

다음은 성능 문제가 많은 스크립트입니다.

#!/usr/bin/ksh
while read i
do
  x=`echo $i |cut -d"|" -f2`
  rem=`expr $x % 62`
  echo "reminder is " $rem
  quo=`expr $x / 62`
  echo "quotiont is " $quo

  grp_rem=" "
  if [[ ${#quo} -ge 2 ]]
  then
    while [ $quo -ge 62 ]
    do
      sub_rem=`expr $quo % 62`
      quo=`expr $quo / 62`
      grp_rem=`echo $sub_rem" "$grp_rem`
    done
  fi
  echo $i"|"$quo" "$grp_rem" "$rem >> base62_while.out
done < base62_while.txt

어쨌든 위 스크립트를 사용하여 성능을 향상시킬 수 있습니까?

입력 예:

1|5147634738948389685

샘플 출력

1|5147634738948389685|6 8 16 13 46 17 20 35 9 49 43

답변1

외부 도구를 호출할 필요가 없습니다. ksh가 산술을 수행할 수 있습니다. 또한 나머지를 저장하기 위해 배열을 사용합니다.

#!/usr/bin/ksh
div=62
while IFS='|' read -r n x; do
    rem=$(( x % div ))
    quo=$(( x / div ))
    echo "reminder is  $rem" >&2
    echo "quotiont is  $quo" >&2

    remainders=( $rem )
    while (( quo >= div )); do
        sub_rem=$(( quo % 62 ))
        quo=$(( quo / 62 ))
        echo "reminder is  $sub_rem" >&2
        echo "quotiont is  $quo" >&2
        remainders=( $sub_rem "${remainders[@]}" )
    done
    echo "$n|$x|$quo ${remainders[*]}"

    x=$quo
    for r in "${remainders[@]}"; do
        x=$(( x * div + r ))
    done
    echo Verification: $x
done <<END
1|5147634738948389685
END

답변2

훨씬 빨라야 해요

#!/usr/bin/ksh
#
while IFS='|' read n x
do
    base62="$(echo "obase=62; $x" | bc | sed -re 's/ 0/ /g' -e 's/^ //')"
    printf "%d|%s|%s\n" $n "$x" "$base62"
done <base62_while.txt >>base62_while.out

base62줄은 bc10진수 소스 숫자를 해당하는 기본 62 숫자로 변환합니다. 선행 0을 제거하는 두 자리 십진수 쌍을 출력합니다(즉 , 02로 다시 작성 2하지만 45변경되지 않은 상태로 유지).

입력하다

1|5147634738948389685

산출

1|5147634738948389685|6 8 16 13 46 17 20 35 9 49 43

답변3

수행할 수 있는 작업(및 속도 향상)은 다음과 같습니다.

  • 원래 1000개 숫자
    35.023초
  • 모든 expr 명령을 산술 확장으로 대체 $((x%62))
    14.473
  • 3.131 grp_rem=`echo $sub_rem" "$grp_rem`로 변환grp_rem="$sub_rem $grp_rem"
  • cut( set IFS='|'; set -f; 및 set -- $1) 을 사용하여 쉘 분할을 사용하지 마십시오.
    • IFS='|' read a x <<<"$i"또는 ( <<<임시 파일을 생성하는 동안) 사용
    • 이미 사용되었으므로 읽기를 교체하십시오.
      0.454
  • 하나의 루프로 줄이고(if 제거) 끝에 후행 공백
    0.207을 제거합니다.
  • $((...))
    두 개의 0.113 ---- 쉘을 연결하는 루프를 더 단단하게 만듭니다
    . 변경 시간은 35.023초보다 약 300배 빠릅니다.
    ++++ 이것은 아마도 쉘 스크립트로 할 수 있는 가장 좋은 일일 것입니다.
  • awk 0.123으로 변경
    ---- awk: 전체 변경 사항이 약 280배 빨라졌습니다.

결과 스크립트:

#!/usr/bin/ksh
while IFS='|' read a b             # read both values split on '|'
do
    x=$b                           # set value of x (quotient)
    grp_rem=""                     # clear value of group
    while (( rem=x%62 , x/=62 ))   # do both math expressions.
    do
        grp_rem="$rem $grp_rem"    # concatenate resulting values
    done
    grp_rem=${grp_rem%?}           # remove one character (an space)
    echo "$a|$b|$rem $grp_rem" 
done  < base62_while.txt  >> base62_while.out

awk 스크립트와 동일합니다. 이것이 더 빠른 awk 스크립트인지는 모르겠지만 잘 작동합니다. 쉘보다 10,000개 이상의 라인이 빠릅니다. 노트:-M이는 제공한 19자리 순서대로 숫자를 처리하는 데 필요한 (임의 정밀도) 옵션과 함께 GNU awk를 사용하는 것입니다 . 더 긴 숫자를 처리할 수 있습니다. 얼마나 오래 걸리는지는 확인하지 않았지만 한도가 꽤 높다고 확신합니다. :-) awk는 이 옵션을 포함하여 컴파일해야 합니다( awk 'BEGIN{ print( PROCINFO["gmp_version"], PROCINFO["prec_max"]) }'다음으로 확인하세요).

awk -MF'|' '{ x=$2; grp_rem="";
              while(x>0){
                          rem=x%62;
                          x=int(x/62);
                          grp_rem=rem" "grp_rem
                        }
              printf("%-22s|%s\n",$0,grp_rem)
            }
           ' <base62_while.txt >>base62_while.out

답변4

그리고 dc:

sed 's/.*|\(.*\)/[&|]P\1p/;1s/^/62o/' base62_while.txt | dc > base62_while.out

또는 bc( 의 역사적 구현은 bc실제로 의 래퍼라는 점에 유의하십시오 dc):

sed 's/.*|\(.*\)/"&|";\1/;1s/^/obase=62;/' base62_while.txt | bc > base62_while.out

주의해서 dcbc출력 줄을 감싸십시오. GNU 구현을 사용하면 이러한 상황을 방지하기 위해 DC_LINE_LENGTHBC_LINE_LENGTH환경 변수를 0으로 설정할 수 있습니다.

$ echo '1|167883826163764944817996215305490271305728' | sed 's/.*|\(.*\)/[&|]P\1p/;1s/^/62o/' | dc
1|167883826163764944817996215305490271305728| 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\
 00
$ echo '1|167883826163764944817996215305490271305728' | sed 's/.*|\(.*\)/[&|]P\1p/;1s/^/62o/' | DC_LINE_LENGTH=0 dc
1|167883826163764944817996215305490271305728| 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

관련 정보