次のコードのパフォーマンスを向上させる方法

次のコードのパフォーマンスを向上させる方法

以下はパフォーマンスの問題が多いスクリプトです。

#!/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桁に変換します。先行ゼロを削除する2桁の10進数のペアを出力します(つまり、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.131grp_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
  • 1つのループに減らし(ifを削除)、最後に末尾のスペース
    0.207を削除します。
  • $((...))
    2つの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

注意してdc長いbc出力行を包みます。 GNU 実装では、このような状況を避けるため、DC_LINE_LENGTH環境BC_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

関連情報