我有一个awk脚本,用于计算一些事务完成所需的时间。脚本获取每个事务的唯一ID,并存储每个事务的最小和最大时间戳。然后它计算差值,最后显示超过60秒的结果。
当与数千(20万)人一起使用时,它效果很好,但在现实世界中使用时需要更多的时间。我对它进行了几次测试,处理大约2800万条线路大约需要15分钟。我能认为这是一个好的表现吗?还是有可能改进它?
我对任何建议都持开放态度。
这里有完整的代码
zgrep -E "(([a-z0-9]){15,}:" /path/to/very/big/log | awk '{
gsub("[()]|:.*","",$4); #just removing ugly chars
++cont
min=$4"min" #name for maximun value of current transaction
max=$4"max" #same as previous, just for readability
split($2,secs,/[:,]/) #split hours,minutes and seconds
seconds = 3600*secs[1] + 60*secs[2] + secs[3] #turn everything into seconds
if(arr[min] > seconds || arr[min] == 0)
arr[min]=seconds
if(arr[max] < seconds)
arr[max]=seconds
dif=arr[max] - arr[min]
if(dif > 60)
result[$4] = dif
}
END{
for(x in result)
print x" - "result[x]
print ":Processed "cont" lines"
}'
您不需要每次读取记录时都计算dif。只需在END部分中执行一次即可。
您不需要那个cont变量,只需使用NR.即可
您不需要分别填充最小值和最大值。字符串串联在awk中很慢。
您不应该更改$4,因为这将强制重新编译记录。
试试这个:
awk '{
name = $4
gsub(/[()]|:.*/,"",name); #just removing ugly chars
split($2,secs,/[:,]/) #split hours,minutes and seconds
seconds = 3600*secs[1] + 60*secs[2] + secs[3] #turn everything into seconds
if (NR==1) {
min[name] = max[name] = seconds
}
else {
if (min[name] > seconds) {
min[name] = seconds
}
if (max[name] < seconds) {
max[name] = seconds
}
}
}
END {
for (name in min) {
diff = max[name] - min[name]
if (diff > 60) {
print name, "-", diff
}
}
print ":Processed", NR, "lines"
}'
经过一些测试,并根据Ed Morton给出的建议(包括代码改进和性能测试),我发现瓶颈是zgrep命令。下面是一个做了几件事的例子:
- 检查我们是否有交易行(第一个如果)
- 清除事务id
- 通过检查它是否在数组中来检查它是否已经注册(第二个if)
- 如果未注册,则检查它是否是合适的事务类型,如果是,则以秒为单位注册时间戳
- 如果已注册,则将新时间戳保存为最大值
- 毕竟,它进行了必要的运算来计算时差
非常感谢所有帮助我的人。
zcat /veryBigLog.gz | awk '
{if($4 ~ /^([:alnum:]/ ){
name=$4;gsub(/[()]|:.*/,"",name);
if(!(name in min)){
if($0 ~ /TypeOFTransaction/ ){
split($2,secs,/[:,]/)
seconds = 3600*secs[1] + 60*secs[2] + secs[3]
max[name] = min[name]=seconds
print lengt(min) "new "name " start at "seconds
}
}else{
split($2,secs,/[:,]/)
seconds = 3600*secs[1] + 60*secs[2] + secs[3]
if( max[name] < seconds) max[name]=seconds
print name " new max " max[name]
}
}}END{
for(x in min){
dif=max[x]- min[x]
print max[x]" max - min "min[x]" : "dif
}
print "Processed "NR" Records"
print "Found "length(min)" MOs" }'