需要: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 字节的 datastr 开始(大多数时候 datumlen < 5),然后从那里向上推。我可以流式输出结果,所以我不担心代码的内存要求,但我可能需要对 datastr 进行多次传递,所以我想避免流式传输 datastr (除非更快)。

所以问题是:是否有内存和访问效率高的例程可以改进示例 1 并且看起来类似于示例 2?或者我最好相信内部缓冲 AWK 和系统用于处理输入文件,并且只对同一个输入文件进行多次传递?

编辑2015.09.18:(我还没有在这个论坛注册,所以在这里回答评论。)我在非Unix平台上使用gawk 4.1.3。我对拥有一个小型便携式环境来执行某些类型的计算感兴趣。我对 gawk 的内部结构了解不够,并且认为也许阅读此论坛的人以前尝试过类似的事情。如果我没有收到其他建议,我最终会分析不同的方式。编辑结束 2015.09.18

Gerhard“询问我有关系统调整的问题”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

所以我决定缓冲这部分。

我预计第二部分和第三部分(ATEST=2 和 3)的执行速度比第一部分快一些。但那并没有发生。使用数组似乎总是快一点,极端情况下大约是第 2 节的两倍,比第 3 节快一点。但是,数组版本使用了大约 10 倍(或更多)的内存,因为必须将索引存储为以及价值观。

我最初在没有 DATAMAXLEN 值的情况下测试了第 2 部分,由于重复的 substr() 调用,速度变得非常慢。第 2 节方法绝对不会提供更高的速度,尽管它确实节省了输入数据使用的内存。

总之,如果您有内存需要消耗,请使用关联数组。如果您有一个好的磁盘,请从文件中读取。如果你必须保存,请爬过绳子,但要小心,只看小碎片。在我的系统上,我可能会遇到内存限制,因此我可能会从应用程序的文件中读取数据。如果有人看到一种调整第 2 部分的方法,比如使用索引或其他一些节省内存的方法来访问字符串,我想知道它。

格哈德“我的里程经常变化”帕斯曼,2015.09.30

相关内容