Строка чтения Chicken Scheme занимает слишком много времени

Есть ли быстрый способ чтения и токенизации большого корпуса? Я пытаюсь прочитать умеренно большой текстовый файл, и скомпилированный CHICKEN, кажется, просто зависает (я убил процесс примерно через 2 минуты), тогда как, скажем, Racket работает приемлемо (около 20 секунд). Могу ли я что-нибудь сделать, чтобы получить такую ​​же производительность на CHICKEN? Это код, который я использую для чтения файла. Все предложения приветствуются.

(define *corpus*
  (call-with-input-file "largeish_file.txt"
    (lambda (input-file)
      (let loop ([line (read-line input-file)]
                 [tokens '()])
        (if (eof-object? line)
            tokens
            (loop (read-line input-file)
                  (append tokens (string-split line))))))))

person lazy evaluator    schedule 10.07.2020    source источник


Ответы (2)


Попробуйте запустить его с большей начальной кучей:

./prog -:hi100M

Программа выполняет много аллокаций, а это означает, что куча должна быть сильно изменена, что вызывает множество крупных сборщиков мусора (и это дорого).

Вы можете увидеть изменения размеров кучи, когда вы включаете отладочный вывод:

./prog -:d

Если вы хотите увидеть вывод GC, попробуйте:

./prog -:g

person sjamaan    schedule 10.07.2020
comment
Настройка других параметров GC также может иметь смысл (попробуйте -:? для справки о доступных параметрах времени выполнения; они также в руководстве, кстати). - person sjamaan; 10.07.2020

Если вы можете позволить себе прочитать весь файл в память за один раз, вы можете использовать что-то вроде следующего кода, который должен быть быстрее:

(let loop ((lines (with-input-from-file "largeish_file.txt"
                    read-lines)))
  (if (null? lines)
      '()
      (append (string-split (car lines))
              (loop (cdr lines)))))

Вот некоторый код быстрого теста:

(import (chicken io)
        (chicken string))

;; Warm-up
(with-input-from-file "largeish_file.txt" read-lines)

(time
 (with-output-to-file "a.out"
   (lambda ()
     (display
      (call-with-input-file "largeish_file.txt"
        (lambda (input-file)
          (let loop ([line (read-line input-file)]
                     [tokens '()])
            (if (eof-object? line)
                tokens
                (loop (read-line input-file)
                      (append tokens (string-split line)))))))))))

(time
 (with-output-to-file "b.out"
   (lambda ()
     (display
      (let loop ((lines (with-input-from-file "largeish_file.txt"
                          read-lines)))
        (if (null? lines)
            '()
            (append (string-split (car lines))
                    (loop (cdr lines)))))))))

И вот результаты на моей системе:

$ csc bench.scm && ./bench
28.629s CPU time, 13.759s GC time (major), 68772/275 mutations (total/tracked), 4402/14196 GCs (major/minor), maximum live heap: 4.63 MiB
0.077s CPU time, 0.033s GC time (major), 68778/292 mutations (total/tracked), 10/356 GCs (major/minor), maximum live heap: 3.23 MiB

Просто убедитесь, что мы получили одинаковый результат из обоих фрагментов кода:

$ cmp a.out b.out && echo They contain the same data
They contain the same data

largeish_file.txt был сгенерирован путем обработки файла системного журнала ~ 100 КБ, пока он не получил ~ 10000 строк (упомянем об этом, чтобы вы получили представление о профиле входного файла):

$ ls -l largeish_file.txt
-rw-r--r-- 1 mario mario 587340 Aug  2 11:55 largeish_file.txt

$ wc -l largeish_file.tx
5790 largeish_file.txt

Результаты, которые я получил, используя CHICKEN 5.2.0 в системе Debian.

person mario-goulart    schedule 02.08.2020