2013-07-28 29 views
2

为了比较Agda programming language与Tcl脚本语言的速度,我正在执行一个小小的速度测试。它的科学工作,这只是一个预测试,而不是一个真正的考验。无论如何,我都没有尝试进行实际的速度比较!解析整数列表(速度测试所需的优化)

我想出了一个小例子,其中Agda比Tcl快10倍。我使用这个例子有特殊的原因。我主要担心的是我的Tcl代码编程糟糕,这是Tcl在这个例子中比Agda慢的唯一原因。

代码的目标是解析表示整数列表的行,并检查它是否确实是一个整数列表。
示例“(1,2,3)”将是一个有效的列表。
示例“(1,a,3)”不是有效的列表。

我的输入是一个文件,我检查文件的每第三行(第三行)。如果任何行不是整数列表,程序将打印“false”。

我的输入文件:

(613424,505980,317647,870930,75580,897160,716297,668539,689646,196362,533020) 


(727375,472272,22435,869407,320468,80779,302881,240382,196077,635360,568517) 


(613424,505980,317647,870930,75580,897160,716297,668539,689646,196362,533020) 

(但是,我真正的考验文件大约3兆字节大)

我目前TCL代码来解决这个问题:

package require Tcl 8.6 

proc checkListNat {str} { 
    set list [split [string map {"(" "" ")" ""} $str] ","] 
    foreach l $list { 
     if {[string is integer $l] == 0} { 
      return 0 
     } 
    } 
    return 1 
} 

set i 1 
set fp [open "/tmp/test.txt" r] 
while { [gets $fp data] >= 0 } { 
    incr i 
    if { [expr $i % 3] == 0} { 
     if { [checkListNat $data] == 0 } { 
      puts "error" 
     } 
    } 
} 
close $fp 

如何我可以优化当前的Tcl代码,以便Agda和Tcl之间的速度测试更加真实吗?

+0

我会使用'字符串范围$ str 1 end-1'而不是字符串映射。另外,'if'条件已经是一个表达式,所以你只需要'if {$ i%3 == 0}'而不用调用expr。 –

+0

@glenn请注意'expr'是无支撑的... –

+0

嗨@唐纳,我不明白你的评论。这不等于'[expr [expr $ i%3] == 0]'? –

回答

2

首先要做的事在程序(或lambda条款)尽可能多的代码确保所有表达式都支持。那是你们两个关键的问题,都是表现不佳。我们也会做一些其他的事情(在if测试中你几乎不需要expr,这不是其中之一,string trimstring map更合适,string is真的应该用-strict来完成)。有了这些,我就可以得到这个版本,这个版本与你已经拥有的版本应该相当类似,而且应该具有更高的性能。

package require Tcl 8.6 

proc checkListNat {str} { 
    foreach l [split [string trim $str "()"] ","] { 
     if {[string is integer -strict $l] == 0} { 
      return 0 
     } 
    } 
    return 1 
} 

apply {{} { 
    set i 1 
    set fp [open "/tmp/test.txt" r] 
    while { [gets $fp data] >= 0 } { 
     if {[incr i] % 3 == 0 && ![checkListNat $data]} { 
      puts "error" 
     } 
    } 
    close $fp 
}} {*}$argv 

可能加入fconfigure $fp -encoding iso8859-1获得更好的性能;你必须自己测试一下。但关键的变化是由于前面大胆的项目所致,因为每个变化都会大大影响所用编译策略的效率。 (另外,Tcl 8.5比8.6有点快 - 8.6有一个完全不同的执行引擎,对某些事情来说有点慢 - 所以你也可以用8.5来测试新代码;代码本身似乎对两个版本都有效。 )

+0

谢谢你的回答! Tcl的人总是那么棒! – mrsteve

1

尝试使用regex {^[0-9,]+$} $line而不是checkListNat函数进行检查。

更新 这里有一个例子

回声 “87566,45,67 \ n56,5r5,45”>!尝试

...

while {[gets $fp line] >0} { 
if {[regexp {^[0-9]+$} $line] >0 } { 
    puts "OK $line" 
} else { 
    puts "BAD $line" 
} 
} 

给出:

> OK 87566,45,67

> BAD 56,5r5,45

+0

感谢您快速回答!真! – mrsteve