下面的代码在5GB文件上运行,它消耗99%的CPU,我想知道我是在做一些非常错误的事情,或者任何事情都可以改善执行时间。
2013-04-03 08:54:19,989 INFO [Logger] 2013-04-03T08:54:19.987-04:00PCMC.common.manage.springUtil< log-message-body>< headers>& lt ; fedDKPLoggingContext id =" DKP_DumpDocumentProperties"类型=" context.generated.FedDKPLoggingContext"&安培; GT;&安培; LT; logFilter&安培;大于7&安培; LT / logFilter&安培; GT;&安培; LT; logSeverity&安培; GT; 255&安培; LT / logSeverity&安培; GT;&安培; LT;的SchemaType&安培; GT; PCMC.MRP.DocumentMetaData&安培; LT; /的SchemaType&安培; GT;&安培; LT; UID&安培; GT; 073104c-4E-4CE-BDA-694344ee62&安培; LT; / UID&安培; GT;&安培; LT; consumerSystemId& gt; JTR& lt; / consumerSystemId& gt;& lt; consumerLogin& gt; jbserviceid& lt; / consumerLogin& gt;& lt; logLocation& gt;成功完成服务& lt; / logLocation& GT;&安培; LT / fedDKPLoggingContext&安培; GT;< /集管和GT;&LT有效载荷GT; 0℃; /有效载荷GT;< /登录消息体>
这是我正在使用的代码。我尝试使用gz格式,但都是徒劳的。我在下面的命令中用bash称这个awk。
awk -f mytest.awk<(gzip -dc scanning-file。$ yesterday.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 ("%s\n", newtime)
return time_ms
}
{
stid = gensub(/.*UID>([^&]+).*/,"\\1","")
}
(stid in starttime) {
etime = to_ms($2)
endtime[stid] = etime
docid[stid] = gensub(/.*id="([^""]+).*/,"\\1","")
consumer[stid]= gensub(/.*schemaType>PNC.([^.]+).*/,"\\1","")
state[stid]= gensub(/.*lt;logLocation>([^'' ]+).*/,"\\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]
}
}
}
}
答案 0 :(得分:3)
在END
部分,它始终通过内部for-loop,即使找到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带宽。
答案 1 :(得分:3)
假设每个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 = whatever }
stid in starttime {
populate endtime[stid]
next
}
{ populate starttime[stid] }
END {
for (stid in endtime) {
process endtime[stid] - starttime[stid]
}
}
无论采用哪种方法,您都应该看到性能大幅提升。
答案 2 :(得分:0)
@ 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 就像离开这个爆发来自毫秒和stid。
561849 c858591f-e01b-4407-b9f9-48302b65c383 562740 c858591f-e01b-4407-b9f9-48302b65c383 563629 56c71ef3-d952-4261-9711-16b18a32c6ba 564484 56c71ef3-d952-4261-9711-16b18a32c6ba