为什么 MIT-Scheme 写出数据这么慢?

Why is MIT-Scheme so slow in writing out data?

在一个较大的程序中,我正在写出一小组 (10^7) 的数字 (0...9)。在 2.6GHz CPU 上使用 MIT-Scheme 10.1.10 时速度非常慢,大约需要 2 分钟。

可能我做错了什么,比如没有缓冲,但在阅读参考指南后我很困惑。我将一切都减少到最低限度:

(define (write-stuff port)
  (define (loop cnt)
    (if (> cnt 0)
        (begin (display "0" port)
               (loop (- cnt 1)))))
  (loop 10000000))

(call-with-output-file "tmp.txt" write-stuff)

欢迎任何提示...

[编辑] 为清楚起见:数据条目彼此无关,并存储在二维向量中。它们可以被认为是随机的,所以我不喜欢将它们分组(它是一个接一个或一次全部)。您可以考虑将数据定义为

(define (data width height)
  (make-initialized-vector width (lambda (x) 
    (make-initialized-vector height (lambda (x) 
      (list-ref (list #[=11=] #) (random 2)))))))

显然,kernel/user-switch 需要很多时间,所以最好将其转换为 1 个字符串,并像 @ceving 建议的那样一次性写出。然后它对我来说足够快了,即使它仍然是 20s 16MB。

(define (data->str data)
  (string-append* (vector->list (vector-map vector->string data))))

(define dataset (data 4096 4096))

(call-with-output-file "test.txt" (lambda (p) 
  (display (data->str dataset) p)))

问题不在于 MIT-Scheme 太慢了。问题是,您过度调用了内核函数 write。您的程序为每个字符从用户模式切换到内核模式。这需要很多时间。如果您在 Bash 中执行相同操作,则需要更长的时间。

您的方案版本:

(define (write-stuff port)
  (define (loop cnt)
    (if (> cnt 0)
        (begin (display "0" port)
               (loop (- cnt 1)))))
  (loop 10000000))
(call-with-output-file "mit-scheme-tmp.txt" write-stuff)
(exit)

运行 Scheme 版本的包装器:

#! /bin/bash
mit-scheme --quiet --load mit-scheme-implementation.scm

在我的系统上大约需要 1 分钟:

$ time ./mit-scheme-implementation 

real    1m3,981s
user    1m2,558s
sys     0m0,740s

Bash也一样:

#! /bin/bash
: > bash-tmp.txt
n=10000000
while ((n > 0)); do
  echo -n 0 >> bash-tmp.txt
  n=$((n - 1))
done

需要 2 分钟:

$ time ./bash-implementation 

real    2m25,963s
user    1m33,704s
sys     0m50,750s

解决方法是:不执行1000万次内核态切换

只执行一次(或至少少执行 4096 次):

(define (write-stuff port)
  (display (make-string 10000000 #[=15=]) port))

(call-with-output-file "mit-scheme-2-tmp.txt" write-stuff)
(exit)

程序只需要 11 秒。

$ time ./mit-scheme-implementation-2 

real    0m11,390s
user    0m11,270s
sys     0m0,096s

这就是在 C 库中发明缓冲的原因: https://www.gnu.org/software/libc/manual/html_node/Stream-Buffering.html#Stream-Buffering