5

while ループを使用してタスクを処理していましたが、

約1,000万行の大きなファイルからレコードを読み取ります。

時間が経つにつれて、処理がますます遅くなることがわかりました。

100 万行のシミュレート スクリプトを作成すると、問題が明らかになります。

readコマンドはどのように機能しますか?

seq 1000000 > seq.dat
while read s;
do
    if [ `expr $s % 50000` -eq 0 ];then
        echo -n $( expr `date +%s` - $A) ' ';
        A=`date +%s`;
    fi
done < seq.dat

端末は時間間隔を出力します。

98 98 98 98 98 97 98 97 98 101 106 112 121 121 127 132 135 134

50,000行くらいになると明らかに処理が遅くなります。

4

2 に答える 2

5

あなたのコードを使用して、同じパターンの増加する時間を見ました (最初から!)。より高速な処理が必要な場合は、シェルの内部機能を使用して書き直す必要があります。これが私のbashバージョンです:

tabChar="   "  # put a real tab char here, of course
seq 1000000 > seq.dat
while read s;
do
    if (( ! ( s % 50000 ) )) ;then
        echo $s "${tabChar}" $( expr `date +%s` - $A) 
        A=$(date +%s);
    fi
done < seq.dat

修正されたバグを編集 し、各行が処理されていることを出力が示していましたが、50000 行ごとにタイミング処理が行われるようになりました。ドアー!

だった

  if ((  s % 50000 )) ;then

に固定

  if (( ! ( s % 50000 ) )) ;then

今すぐ出力echo ${.sh.version} =バージョン JM 93t+ 2010-05-24

50000
100000   1
150000   0
200000   1
250000   0
300000   1
350000   0
400000   1
450000   0
500000   1
550000   0
600000   1
650000   0
700000   1
750000   0

出力バッシュ

50000    480
100000   3
150000   2
200000   3
250000   3
300000   2
350000   3
400000   3
450000   2
500000   2
550000   3
600000   2
650000   2
700000   3
750000   3
800000   2
850000   2
900000   3
950000   2
800000   1
850000   0
900000   1
950000   0
1e+06    1

元のテストケースに時間がかかる理由については...よくわかりません。各テスト サイクルの時間と時間の増加の両方を見て驚きました。これを本当に理解する必要がある場合は、より多くのテストを計測するために時間を費やす必要があるかもしれません。たぶん、何かが実行されているtrussか、またはstrace(ベースOSに応じて)表示されるでしょう。

これが役立つことを願っています。

于 2012-04-28T16:08:03.207 に答える
4

「Learning the Korn Shell」の著者が指摘しているように、読み取りは比較的遅いプロセスです*。awk(セクション 7.2.2.1 のすぐ上。)やなど、sed本質的に同じことを行うために高度に最適化された他のプログラムがあります。つまり、ファイルから一度に 1 行ずつ読み取り、その入力を使用していくつかの操作を実行します。

言うまでもなく、減算を行ったりモジュラスを取得したりするたびに外部プロセスを呼び出しているため、コストがかかる可能性があります。 awk両方の機能が組み込まれています。

次のテストが指摘しているように、awkかなり高速です。

#!/usr/bin/env bash

seq 1000000 | 
awk '
  BEGIN {
    command = "date +%s"
    prevTime = 0
  }
  $1 % 50000 == 0 {
    command | getline currentTime
    close(command)

    print currentTime - prevTime
    prevTime = currentTime
  }
'

出力:

1335629268
0   
0   
0   
0   
0   
0   
0   
0   
0   
0   
0   
0   
0   
0   
1   
0   
0   
0   
0

最初の数字は と同等であることに注意してくださいdate +%s。あなたのテストケースと同じように、最初の一致を許可します。

ノート

*はい、著者は Korn シェルについて話しています。OP がタグ付けした bash ではありませんが、bash と ksh は多くの点で似ています。ksh は実際には bash のスーパーセットです。したがって、読み取りコマンドはシェルごとに大幅に異なるわけではないと思います。

于 2012-04-28T15:40:33.017 に答える