Почему MIT-Scheme так медленно записывает данные? - PullRequest
0 голосов
/ 19 июня 2020

В более крупной программе я выписываю небольшой набор (10 ^ 7) числовых цифр (0 ... 9). Это происходит очень медленно с MIT-Scheme 10.1.10 на процессоре с тактовой частотой 2,6 ГГц, что занимает примерно 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)

Любые подсказки приветствуются ...

[EDIT] Чтобы прояснить ситуацию: записи данных не связаны друг с другом, и хранятся в 2D-векторе. Их можно считать случайными, поэтому я не люблю группировать их (по одному или все сразу). Вы можете считать, что данные определяются чем-то вроде

(define (data width height)
  (make-initialized-vector width (lambda (x) 
    (make-initialized-vector height (lambda (x) 
      (list-ref (list #\0 #\1) (random 2)))))))

По-видимому, переключение ядра / пользователя занимает много времени, поэтому лучше преобразовать это в 1 строку и записать ее одним кадром, например @ предложил ceving. Тогда он у меня работает достаточно быстро, хотя для 16 МБ все еще 20 секунд.

(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)))

1 Ответ

3 голосов
/ 20 июля 2020

Проблема не в том, что 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)

Обертка для запуска версии схемы:

#! /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

Решение : не выполнять 10 миллионов переключений режима ядра.

Выполнять только один (или, по крайней мере, в 4096 раз меньше):

(define (write-stuff port)
  (display (make-string 10000000 #\0) 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

...