在mzscheme中的I/O性能

4
作为一名Linux管理员,我通常用Bash、TCL,较少使用Perl编写脚本。出于好奇,我试着用mzscheme写了一些东西,但发现它的性能要差得多。我将脚本简化为仅读取一个500MB的日志文件:
#lang scheme
(require rnrs/programs-6)
(call-with-input-file (vector-ref (current-command-line-arguments) 0)
    (lambda (in)
            (let loop ((line (read-line in)))
                    (unless (eof-object? line)
                            (loop (read-line in))))))

这个简单的过程大约需要40秒。适用于Guile的相同脚本可以在10秒内执行。TCL版本运行时间为5秒。Chicken Scheme仅需3.8秒,比MZScheme少了十倍:

#!/usr/bin/csi -script
(call-with-input-file (list-ref (command-line-arguments) 0)
    (lambda (in)
            (let loop ((line (read-line in)))
                    (if (not (eof-object? line))
                            (loop (read-line in))))))

我做错了什么?有没有关于如何更快地编写 MZScheme 程序的建议?

一些额外的测试:

minaev@minaev:~/1$ time ./t.tcl blog.log

real    0m8.907s
user    0m8.417s
sys     0m0.468s
Mon Oct 31 13:15:19 MSK 2011
minaev@minaev:~/1$ time ./t.scm blog.log # Chicken 4.2.0

real    0m7.678s
user    0m6.896s
sys     0m0.580s
Mon Oct 31 13:15:29 MSK 2011
minaev@minaev:~/1$ time /usr/bin/mzscheme t.ss blog.log # mzscheme 4.2.1

real    0m44.047s
user    0m41.803s
sys     0m0.948s
Mon Oct 31 13:17:03 MSK 2011
minaev@minaev:~/1$ time racket t.ss blog.log  # racket 5.1.3

real    0m25.287s
user    0m23.189s
sys     0m0.828s
Mon Oct 31 13:17:39 MSK 2011
minaev@minaev:~/1$ raco make t.ss
Mon Oct 31 13:17:47 MSK 2011
minaev@minaev:~/1$ time racket t.ss blog.log  # racket 5.1.3 byte-compiled

real    0m23.237s
user    0m22.469s
sys     0m0.688s

出于好奇,你用来比较的确切Tcl脚本是什么?我问这个问题是因为我是一名Tcl黑客... - Donal Fellows
我担心代码会在评论中被破坏,但它非常琐碎,不应该是问题 :) proc parse {log} { set f [open $log] while {[gets $f line] >= 0} { } } parse [lindex $argv 0] - minaev
我正在努力更好地理解这个问题,但我不熟悉TCL。我查阅了TCL手册中的“gets”函数,以便查看字符串是UTF8字符串还是普通字节字符串。但它没有说明——你是否知道在你的示例中TCL是否使用utf8字符串? - soegaard
@soegaard:它会执行,因为我可以看到他没有关闭它。(除了愚蠢的基准测试之外,这几乎是正确的做法……) - Donal Fellows
@soegaard:是的,系统语言环境为UTF-8,因此输入通道已配置为读取UTF-8。 - minaev
2个回答

3
这个问题在 Racket 的开发版本中已经得到了大幅改善。请参见提交记录(此处)以及 Racket 维护者 Matthew Flatt 的信息(此处)。现在它只比 Chicken 慢了约50%,其余的减速主要是由于 Racket 提供的其他功能,例如事件、行计数、Unicode 编码等。

所以,我一问起这个多年的错误就被修复了?我感到很幸运 :) 非常感谢,这让我松了一口气。50%似乎是一个可以接受的价格。 - minaev

1

我尝试重复您的结果,对于Chicken 4.5.0,我得到了大约3.4秒的时间,而对于各种版本的mzscheme/racket,则得到了大约10秒的时间。(我尝试了PLT Scheme 4.2中的mzscheme和Racket 5.1.1以及开发树中的racket,所有编译都在64位模式下进行。)

您使用的是哪个版本的mzscheme?使用的是哪个平台?

您的计时是否可重复?(我想知道块缓存效应。)


我的硬件/软件与您的非常相似。mzscheme是从Ubuntu 10.04存储库安装的,它是v4.2.1 [3m],“x86-64,版本1(SYSV),动态链接(使用共享库),适用于GNU/Linux 2.6.15”。 - minaev
啊哈...我认为输入处理肯定会有一些开销,但是我还是保持原样,因为我希望在各种实现中语义保持一致:Chicken、Racket或TCL。此外,我想处理文本文件,而不仅仅是读取它。有时我可能想对包含西里尔字符的字符串进行操作。 顺便说一句,使用read-bytes-line的变体并没有更快 :) - minaev
@minaev:你能否在你的mzscheme/racket版本中用time包装最后一个表达式并报告它打印了什么?我对CPU和GC时间很感兴趣。 - Ryan Culpepper
@minaev:顺便说一下,在我的机器上使用动态链接版本的Racket导致性能下降了20%(从大约10秒到大约12秒)。 - Ryan Culpepper
@RyanCulpepper:最后一个表达式是 call-with-input-file 吗?这里是它:CPU 时间:24589 实际时间:25398 垃圾回收时间:372。 - minaev
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接