下面的代码在5GB文件上运行,它消耗了99%的CPU,我想知道我是否做错了什么,或者有什么可以改善执行时间。
2013-04-03 08:54:19989 INFO〔Logger〕2013-04-03T08:54:19.987-04:00PCM.common.manage.springUtil<日志消息正文>lt;页眉>amp;lt;fedDKPLoggingContext id="DKP_DumpDocumentProperties"type="context.generated.FedDKPLogingContext"><;日志过滤器>;7</日志过滤器><;logSeverity>;255</logSeverity><;schemaType>;PCMC.MRP.DocumentMetaData</schemaType><;UID>;073104c-4e-4ce-bda-69434ee62</UID><;consumerSystemId>;JTR</consumerSystemId><;consumerLogin>;jbserviceid</consumerLogin><;日志位置>;成功完成服务</日志位置></fedDKPLoggingContext><页眉>lt;有效载荷>0<有效载荷>lt/日志消息正文>
这是我正在使用的代码。我也尝试过gz格式,但都是徒劳的。我在下面的命令中称这个来自bash的awk。
awk-f mytest.awk<(gzip-dc扫描文件。$yeth.gz)|gzip>tem.gz
cat mytest.awk
#!/bin/awk -f
function to_ms (time, time_ms, s) {
split(time, s, /:|,/ )
time_ms = (s[1]*3600+s[2]*60+s[3])*1000+s[4]
#printf ("%sn", newtime)
return time_ms
}
{
stid = gensub(/.*UID&gt;([^&]+).*/,"\1","")
}
(stid in starttime) {
etime = to_ms($2)
endtime[stid] = etime
docid[stid] = gensub(/.*id="([^""]+).*/,"\1","")
consumer[stid]= gensub(/.*schemaType&gt;PNC.([^.]+).*/,"\1","")
state[stid]= gensub(/.*lt;logLocation&gt;([^'' ]+).*/,"\1","")
next
}
{
stime = to_ms($2)
starttime[stid] = stime
st_hour[stid] = stime/(60*60*1000)
timestamp[stid] = $1" "$2
}
END {
print "Document,Consumer,Hour,ResponseTime,Timestamp,State"
for (x in starttime) {
for (y in endtime) {
if (x==y) {
diff = (endtime[y]-starttime[x])
st = sprintf("%02d", st_hour[x])
print docid[y], consumer[y], st":00", diff, timestamp[x], state[y] |"sort -k3"
delete starttime[x]
delete endtime[y]
delete docid[y]
delete consumer[y]
delete timestamp[x]
delete state[y]
}
}
}
}
假设每个stid只有一个结束时间-不要建立一个开始时间和结束时间的数组,然后在它们之间循环,只要在达到结束时间时处理stid即可。即不是像今天这样:
{ stid = whatever }
stid in starttime {
populate endtime[stid]
next
}
{ populate starttime[stid] }
END {
for (x in starttime) {
for (y in endtime) {
if (x == y) {
stid = x
process endtime[stid] - starttime[stid]
}
}
}
}
但是这个:
{ stid = whatever }
stid in starttime {
process to_ms($2) - starttime[stid]
delete starttime[stid]
next
}
{ populate starttime[stid] }
如果你不能做到这一点,例如,由于有多个记录具有相同的stid,并且你想从第一个和最后一个记录中获得时间戳,那么将END部分中的循环更改为只循环通过你获得结束时间的stid(因为你已经知道它们有相应的开始时间),而不是试图在starttime和endtime上找到那些巨大循环中的所有stid,例如:
{ stid = whatever }
stid in starttime {
populate endtime[stid]
next
}
{ populate starttime[stid] }
END {
for (stid in endtime) {
process endtime[stid] - starttime[stid]
}
}
无论采用哪种方法,您都应该看到性能的巨大提高。
在END
部分中,它总是经过内部for循环,即使找到了y
项,然后从endtime
数组中删除了它。我建议使用break
跳出内部循环。
另一方面(正如我所见)根本不需要内部循环!它试图在关联数组中查找具有已知关键字的元素。
此外,我可能会建议不要删除找到的项目。在关联数组中查找项目是在恒定的时间内完成的(取决于哈希键生成的算法和生成的重复项目数量),因此从这样的数组中删除项目不一定会加快进程,但删除项目肯定会减慢进程。
所以我可以建议使用这个:
for (x in starttime) {
if (x in endtime) {
diff = (endtime[x]-starttime[x])
st = sprintf("%02d", st_hour[x])
print docid[x], consumer[x], st":00", diff, timestamp[x], state[x] |"sort -k3"
}
}
使用gzip甚至会消耗更多的CPU资源,但您可以腾出一些I/O带宽。
@Ed,第一种方法并没有给我带来预期的结果。就是这样做的
# end time and diff
(stid in starttime)
{ etime = to_ms($2)
diff = etime - stime
print diff,stid
delete starttime[stid]
next }
# Populate starttime
{
stime = to_ms($2)
starttime[stid] = stime
st_hour[stid] = stime/(60*60*1000)
}
o/p就像左这个sud进来了毫秒和stid。
561849 c858591f-e01b-4407-b9f9-48302b65c383562740 c858591f-e01b-4407-b9f9-48302b65c383563629 56c71ef3-d952-4261-9711-16b18a32c6ba564484 56c71ef3-d952-4261-9711-16b18a32c6ba