#prolog #eclipse-clp
Вопрос:
Я сгенерировал большой файл путей через eclipse. Каждая строка содержит предложение для списка из 27 пунктов.
$ wc -l snake_points.pl
240917 snake_points.pl
$ ls -lh snake_points.pl
-rw-rw-r-- 1 carl carl 72M Sep 6 02:39 snake_points.pl
$ head -n 1 snake_points.pl
snake_points([(2, 0, 0), (2, 0, 1), (2, 0, 2), (2, 1, 2), (2, 1, 1), (2, 1, 0), (2, 2, 0), (2, 2, 1), (2, 2, 2), (1, 2, 2), (0, 2, 2), (0, 1, 2), (0, 0, 2), (0, 0, 1), (0, 1, 1), (0, 1, 0), (0, 2, 0), (0, 2, 1), (1, 2, 1), (1, 2, 0), (1, 1, 0), (1, 1, 1), (1, 1, 2), (1, 0, 2), (1, 0, 1), (1, 0, 0), (0, 0, 0)]).
Однако я не могу загрузить файл в память (даже с 8 г кучи):
$ time eclipse -f snake_points.ecl -e 'halt.'
*** Overflow of the global/trail stack in spite of garbage collection!
You can use the "-g kBytes" (GLOBALSIZE) option to have a larger stack.
Peak sizes were: global stack 8388576 kbytes, trail stack 59904 kbytes
________________________________________________________
Executed in 128.05 secs fish external
usr time 122.92 secs 297.00 micros 122.92 secs
sys time 5.01 secs 37.00 micros 5.01 secs
Сравните это с swipl
:
$ time swipl -f snake_points.pl -g 'halt.'
________________________________________________________
Executed in 53.56 secs fish external
usr time 53.27 secs 272.00 micros 53.27 secs
sys time 0.28 secs 41.00 micros 0.28 secs
Ни то, ни другое не впечатляет, но я бы ожидал, что ECLiPSe завершится с разумным объемом памяти.
Является ли это ожидаемым поведением? Что можно сделать?
Я понимаю, что решением может быть «использование базы данных» или EXDR, но разве это не должно быть сделано эффективно?
Ответ №1:
Проблема в том, что вы не только читаете данные, вы пытаетесь скомпилировать их как единый предикат с 240917 предложениями, и компилятор действительно не создан для такого рода использования.
Вместо этого вы можете читать и утверждать предложения из файла данных по одному, например так:
assert_from_file(File) :-
open(File, read, S),
repeat,
read(S, Term),
( Term == end_of_file ->
true
;
assert(Term),
fail
),
!, close(S).
Это загружает ваши данные за конечное время
?- assert_from_file("snake_points.pl").
Yes (19.38s cpu)
и затем вы можете вызвать результирующий предикат, как и ожидалось
?- snake_points(X).
X = [(2, 0, 0), (2, 0, 1), (2, 0, 2), (2, 1, 2), (2, 1, 1), (2, 1, 0), (2, 2, 0), (2, 2, 1), (2, 2, 2), (1, 2, 2), (0, 2, 2), (0, 1, 2), (0, 0, 2), (0, 0, 1), (0, 1, 1), (0, 1, 0), (0, 2, 0), (0, ..., ...), (..., ...), ...]
Yes (0.04s cpu, solution 1, maybe more) ? ;
Но какую бы проблему вы ни пытались решить, это не выглядит как самый многообещающий подход…
Комментарии:
1. Не было бы проще просто написать файл с директивами a
dynamic/1
и aninclude/1
, объявляющимиsnake_points/1
предикат динамическим и включающими исходныйsnake_points.pl
файл?2. @Paulo, к сожалению, нет. Компилятор, как написано в настоящее время, все еще всасывает все предложения для предиката за один раз, вызывая проблему.
3. Использование
dynamic/1
иinclude/1
фактически завершено с 8 ГБ примерно за ~60 секунд.4. Использование
assert_from_file
в комплекте с 1 ГБ за ~22 секунды. Использованиеassert_from_file
с предложением @PauloMoura привело к лучшей производительности с 1 ГБ менее чем за 9 секунд!
Ответ №2:
Вы пробовали изменить представление очков? Использование ','/2
для представления кортежей с более чем двумя элементами на кортеж-плохая идея. Обратите внимание, что:
[eclipse 30]: write_canonical((1,2,3)).
','(1, ','(2, 3))
Yes (0.00s cpu)
Попробуйте вместо этого, например p(1,2,3)
. Это должно немного снизить требования к памяти и может иметь значение.
Комментарии:
1. Это сокращает использование памяти до ~500 МБ и завершается за 40 секунд. Спасибо!