必須:AWKの非連想配列

必須:AWKの非連想配列

配列表現の代わりに内部文字列表現を直列化して、AWKでいくつかのコードをスピードアップするつもりです。 (以下の例1と2では、datasepが単一文字であり、計算可能なデータの一部ではないと仮定しています。)したがって、代わりに:

# Example 1
split(datastr,data,datasep)
for(i=1; i in data; i++) { 
     # Use data[i]
     }

次のようなことを試してみたい

 # Example 2 - buggy code assumes datastr terminated by datasep
 l= length(datastr)
 for(j=1; j < l ; ) {
      datumlen = match(substr(datastr,j+1),datasep)
      #Use substr(datastr,j+1,datumlen-1)
      j+=datumlen
      }

連想配列(データ)の使用に伴うメモリとルックアップ時間を節約したい、またmatchとsubstrの実装方法に自信があるからです。私は長さが10 ^ 6バイトを超えるデータ文字列(ほとんどの場合 datumlen < 5)で始まり、そこから作業する予定です。結果をストリーミングできるので、コードのメモリ要件を心配することはありませんが、datastrに何度も渡す必要があるため、(より速くない限り) datastr ストリーミングを避けたいと思います.

したがって、質問は次のようになります。例1を改善し、例2と同様に見えるメモリとアクセス効率の良いルーチンはありますか?それとも、AWKとシステムが入力ファイル処理のために内部的にバッファリングしていると信じて、同じ入力ファイルに複数回パスする方が良いでしょうか?

EDIT 2015.09.18:(まだこのフォーラムに登録していないので、ここにコメントに答えてください。)私はUnix以外のプラットフォームでgawk 4.1.3を使用しています。私は特定の種類の計算を実行できる小さなポータブル環境に興味があります。私はgawkの内部について十分に知らず、このフォーラムを読んでいる誰かが以前に同様のことを試みたかもしれないと思いました。他の提案を受け取らない場合は、最終的に別の方法で分析します。編集終了 2015.09.18

ゲルハルト「システムチューニングについて聞いてください」 Paseman, 2015.09.16

ベストアンサー1

以下は、質問に答えるために書いたgawk 4.1.3のテストコードです。 PFILEの生データは数値であり、DFILEに連続する項目間の差を格納してデータを圧縮しようとしています。

BEGIN{ RLS=bufstr=""; SEP =":" ; PFILE="somenumbers.txt" ; DFILE= "diffile.txt"
if (ATEST=="") ATEST=1
accumulate=lastdatum=0 ; BIGN=5500000 ; DATALENMAX=7 ;TUNELEN=2048
for(i=1; i < BIGN ; i++) {
     getline nextdatum < PFILE
     d = nextdatum -lastdatum
#     RLS = RLS d SEP
     ibuf( d SEP )
     print d > DFILE
     lastdatum=nextdatum  }
# RLS = RLS "0"
ibuf("0")
if (length(bufstr) > 0) { RLS = RLS bufstr ; bufstr="" }
print (RLSlen=length(RLS))
close(PFILE) ; close(DFILE)
timestmp["start"] = systime()
if (ATEST==1){
  split(RLS,data,SEP)
  timestmp["endsplit"] = systime()
  for(i=1; i in data; i++){     accumulate += 1*data[i]     }
  }
if (ATEST==2){
  for(j=1; j<RLSlen ; j+=datalen) {
     datalen=match(substr(RLS,j, DATALENMAX),SEP)
     accumulate  += 1*substr(RLS,j,datalen-1)     }
  }
if (ATEST==3) {
  while((getline diff < DFILE)>0){  accumulate  += 1*diff }
  close(DFILE)
  }
print accumulate 
timestmp["end"] = systime()
for(t in timestmp) print t, (1*timestmp[t] - 1*timestmp["start"])
}

function ibuf(str) {   bufstr=bufstr str
   if (length(bufstr) > TUNELEN) { RLS = RLS bufstr ; bufstr="" }
}

ibuf()関数とTUNELENパラメータはあまり重要ではありません。割り当てのために割り当てられたメモリ値が跳ねるのを見るのは疲れただけです。

RLS = RLS d SEP

それで、この部分を緩衝することにしました。

2番目と3番目の部分(ATEST = 2と3)は、最初の部分より少し速く実行されると予想されます。しかし、そのようなことは起こりませんでした。配列の使用は常に少し速いようです。非常にセクション2よりも約2倍速く、セクション3よりも少し高速です。ただし、配列バージョンは値だけでなくインデックスも格納する必要があるため、約10倍以上のメモリを使用します。

最初はDATAMAXLEN値なしでパート2をテストしましたが、繰り返しのsubstr()呼び出しは非常に遅くなりました。セクション2の方法は、入力データに使用されるメモリを節約しますが、より速い速度を提供しません。

要約すると、消費するメモリがある場合は連想配列を使用してください。ディスクが良好な場合は、ファイルから読んでください。保存する必要がある場合は、ロープの上に上がりますが、注意して小さな部分だけを見てください。私のシステムにはメモリ制約があり、アプリケーションファイルからデータを読み取ることができます。誰かがインデックスを使用したり、文字列にアクセスするためにメモリを節約する他の方法など、パート2を変更する方法を見ている場合は、これについて知りたいです。

ゲルハルト「マイレージが頻繁に変わります」パスのみ、2015.09.30

おすすめ記事