一个文件 ~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