一个文件 ~104 MB 大小,查找匹配特定行并提取内容。
用Tcl代码大致描述如下:
# EBox: M4-M4 [1234,5678..8765,43321] (name,name) Less than minimum edge length
set RE {^EBox: (\S+) \[([\d\.\-,]+)\] \(.*?\) (.+)}
puts [regexp -about $RE] ;# 据说可以预编译正则表达式
set fp [open $file r]
while {[gets $fp line]>=0} {
if {[regexp $RE $line match layer bbox drc_type]} {
foreach {llx lly - urx ury} [split $bbox ".,"] break
lappend bbox_list [list $llx $lly $urx $ury]
}
}
close $fp
上面这部分代码运行时间大致为50秒左右。
已经验证if语句执行块影响可以忽略,主要瓶颈在regexp语句。
改动regexp行为 [regexp $RE $line],运行速度可以提高到10秒左右。
两者的差别仅在于是否提取匹配的子串。对性能影响之大是以前不曾意识到得。原因未明。TODO
最终改动如下,速度同样可以提高到10秒左右。
while {[gets $fp line]>=0} {
if {[regexp $RE $line]} {
set layer [lindex $line 1] ; set bbox [lindex $line 2]
set drc_type [lrange $line 4 end]
foreach {- llx lly - urx ury} [split $bbox {.,[]}] break
lappend bbox_list [list $llx $lly $urx $ury]
}
}
set pattern "EBox:*"
if {[string match $pattern $line]} {
... ...
}
# 或者 #
set pattern "EBox:"
if {[string equal -length [string length $pattern] $pattern $line]} {
...
}
如果把regexp改为string match,运行时间减少到4.6秒左右。
如果regexp改为string equal,运行时间则为5.1秒左右。
好奇着用awk试了一下
/^EBox:/ {
layer = $2;
bbox = $3;
drc_type = substr($0, index($0,")")+2);
#print bbox, layer, drc_type;
n++;
bbox_list[n] = bbox;
}
运行时间在8秒左右。
把上面的awk程序编译成C程序,同样的文件parsing需要的时间是1秒左右。
通过一些不同的方法,程序运行时间可以从50秒缩短到1秒左右。1秒当然还可以更快,但这个探索的过程已经触碰到好几处值得思考和研究的地方。
TODO