← Архив: Common Lisp

Быстрая работа с CSV

Author: · 07.12.2011 17:16
· original author: dmitrys99
Здравствуйте, уважаемые!
Передо мной встала такая задача.
Есть CSV файлы разной структуры, размером от 2 до 200Мб.
Из каждого файла мне надо десяток полей. Порядок полей в файлах меняется и всегда различен, но известен (искать не надо).
Для каждого CSV-файла надо создать XML- и JSON-файлы.
Проблема в том, что надо это сделать быстро.
Я сделал разбор с помощью CL-CSV, а генерацию с помощью with-open-file ... write-string.
Получилось медленно.
Использовал в качестве шаблона для генерации cl-closure-template (по прежнему с помощью write-string) - все-равно медленно.
Как сделать по-другому - не знаю. Ну то есть я понимаю, что надо какую-то буферизацию, но как это сделать на Lisp - не понимаю.
Знания инструментария еще не хватает.
Подскажите направление, пожалуйста!
· original author: archimag
> Подскажите направление
Направление должен подсказать профайлер. В SBCL есть встроенный профайлер. Надо запускать под ним и смотреть что именно тормозит.
> Проблема в том, что надо это сделать быстро
Что значит быстро? И как меряется скорость?
· original author: dmitrys99
Замер делаю (time (fn "file.csv"))
На разбор файла размером 5-7 Мб уходит 10-15 сек. Это много. Хотелось бы уложиться в секунду-полторы, как это делают другие программы.
На C/Delphi я бы по кускам грузил в память блоками по 1-2 Мб, парсил (опять же в памяти) и блоками скидывал на диск.
· original author: vseloved
Можете также попробовать эту библиотеку: http://cybertiggyr.com/dsv/ В свое время для меня работала хорошо, хотя не уверен ан счет скорости...
· original author: dmitrys99
Вопрос быстрой загрузки решился заменой
read-lineна
read-sequence
.
Скорость выросла на порядок.
Теперь появилась другай проблема.
Библиотека либо берет на вход поток, либо строку, которую преобразует в поток с помощью
MAKE-STRING-INPUT-STREAM
и затем читает этот поток с помощью read-line. Получается не быстро. Переписывать библиотеку не хочется, в принципе она работает так, как мне надо.
Но так, как она реализована сейчас - медленно. Других библиотек, которые делают быстро read-line я не нашел.
Видимо, предется переписывать библиотеку. :)
· original author: juna
>Замер делаю (time (fn "file.csv"))
>На разбор файла размером 5-7 Мб уходит 10-15 сек. Это много. Хотелось бы уложиться в секунду-полторы, как это делают >другие программы.
>На C/Delphi я бы по кускам грузил в память блоками по 1-2 Мб, парсил (опять же в памяти) и блоками скидывал на диск.
У меня 7.1 Мб вот такой простой код
(defun csv-to-list (path &optional separator)
  (let (s result)
    (with-open-file
    (stream path
        :direction :input
        :if-does-not-exist :error)
      (loop for line = (read-line stream nil 'foo)
       until (eq line 'foo)
       do
       (progn
         (if separator
         (setf s (cl-ppcre:split  separator line))
         (setf s (cl-ppcre:split  ";" line)))
         (setf result (cons s result)))))
    (reverse result)))
перемалывает:
(time (progn (csv-to-list "/home/juna/wer.csv") t))
Evaluation took:
  2.444 seconds of real time
  2.448153 seconds of total run time (2.296144 user, 0.152009 system)
  [ Run times consist of 0.628 seconds GC time, and 1.821 seconds non-GC time. ]
  100.16% CPU
  5,865,502,488 processor cycles
  172,518,568 bytes consed