Регистрация | Войти
Lisp — программируемый язык программирования
RSS
Размер стека sbcl в slime
juna - 22.10.2011 16:57, Сообщений - 24
Иногда приходится работать с очень длинными списками, соответственно приходится увеличивать объем стека.
В sbcl можно так:

sbcl --control-stack-size 1000

А как это сделать, запуская sbcl из под slime?
[#]
Нужно добавить в .emacs:

(setq slime-default-lisp 'sbcl)
(setq slime-lisp-implementations
      `((sbcl  ("/usr/local/bin/sbcl" "--control-stack-size" "1000") :coding-system utf-8-unix))
)

lithp - 22.10.2011 17:26
[#] Ответ на комментарий от lithp 22.10.2011 17:26
Печаль в том, что так не работает:


; loading #P"/usr/share/common-lisp/source/slime/swank-loader.lisp"
; loading #P"/home/juna/.cache/common-lisp/sbcl-1.0.45.0.debian-linux-x86/usr/share/common-lisp/source/slime/swank/fasl/sbcl-1.0.45.0.debian-linux-x86/swank-backend.fasl"
; loading #P"/home/juna/.cache/common-lisp/sbcl-1.0.45.0.debian-linux-x86/usr/share/common-lisp/source/slime/swank/fasl/sbcl-1.0.45.0.debian-linux-x86/swank-source-path-parser.fasl"
; loading #P"/home/juna/.cache/common-lisp/sbcl-1.0.45.0.debian-linux-x86/usr/share/common-lisp/source/slime/swank/fasl/sbcl-1.0.45.0.debian-linux-x86/swank-source-file-cache.fasl"
; loading #P"/home/juna/.cache/common-lisp/sbcl-1.0.45.0.debian-linux-x86/usr/share/common-lisp/source/slime/swank/fasl/sbcl-1.0.45.0.debian-linux-x86/swank-sbcl.fasl"
STYLE-WARNING: redefining SWANK-BACKEND:SOCKET-FD in DEFUN
STYLE-WARNING: redefining EMACS-INSPECT (#) in DEFMETHOD
; loading #P"/home/juna/.cache/common-lisp/sbcl-1.0.45.0.debian-linux-x86/usr/share/common-lisp/source/slime/swank/fasl/sbcl-1.0.45.0.debian-linux-x86/swank-gray.fasl"
STYLE-WARNING:
   Implicitly creating new generic function STREAM-READ-CHAR-WILL-HANG-P.
; loading #P"/home/juna/.cache/common-lisp/sbcl-1.0.45.0.debian-linux-x86/usr/share/common-lisp/source/slime/swank/fasl/sbcl-1.0.45.0.debian-linux-x86/swank-match.fasl"
; loading #P"/home/juna/.cache/common-lisp/sbcl-1.0.45.0.debian-linux-x86/usr/share/common-lisp/source/slime/swank/fasl/sbcl-1.0.45.0.debian-linux-x86/swank-rpc.fasl"
; loading #P"/home/juna/.cache/common-lisp/sbcl-1.0.45.0.debian-linux-x86/usr/share/common-lisp/source/slime/swank/fasl/sbcl-1.0.45.0.debian-linux-x86/swank.fasl"
WARNING: These Swank interfaces are unimplemented:
 (DISASSEMBLE-FRAME DUP EXEC-IMAGE MAKE-FD-STREAM SLDB-BREAK-AT-START
  SLDB-BREAK-ON-RETURN SOCKET-FD)
;; Swank started at port: 47368.
47368
* mmap: Невозможно выделить память


juna - 22.10.2011 17:45
[#] Ответ на комментарий от juna 22.10.2011 17:45
Цифра задается в мегабайтах.

--control-stack-size megabytes
Size of control stack reserved for each thread in megabytes. Default value is 2. 
lithp - 22.10.2011 17:57
[#] Ответ на комментарий от lithp 22.10.2011 17:57
Ну и что? Вот я и хочу выделить порядка 1 ГБ под стек.
Если запускать в консоли, это вполне возможно, хоть так:


sbcl --control-stack-size 6000

Для проверки генерируем список из 1000000 случайных элементов:


(defun GenRandom (N M)
  (if (> N 0) 
      (cons (random M) (GenRandom (- N 1) M))
      nil))

В терминале sbcl --control-stack-size 1000 трудится, в slime сваливается.
juna - 22.10.2011 18:08
[#] Ответ на комментарий от juna 22.10.2011 18:08
Ну и что? Вот я и хочу выделить порядка 1 ГБ под стек.

да никто не запрещает, ваше дело ;-)

а теперь, если запустить этот код?

(dotimes (i 5)
  (sb-thread:make-thread
    (lambda ()
      (write-line "Test")
      (sleep 3)
)
)
)


lithp - 22.10.2011 18:43
[#] Ответ на комментарий от lithp 22.10.2011 18:43
>а теперь, если запустить этот код?
То памяти на порождаемые процессы не хватит. Хотите сказать, что slime запускается отдельным потоком и ему памяти не хватает?
Ну и как это можно побороть?

Вопрос не такой праздный. Например, вот берем cl-mysql  - она заворачивает запрос в список, если таблица очень большая, то slime валится.

juna - 22.10.2011 19:27
[#] Ответ на комментарий от juna 22.10.2011 19:27
 Хотите сказать, что slime запускается отдельным потоком и ему памяти не хватает?

yep. если лисп реализация поддерживает треды, то SLIME использует их и запускает REPL в отдельном треде.

> Ну и как это можно побороть?

можно покрутить SWANK:*COMMUNICATION-STYLE*, или собрать SBCL без поддержки тредов.

The available communication styles are:

NIL
This style simply loops reading input from the communication socket and serves SLIME protocol events as they arise. The simplicity means that the Lisp cannot do any other processing while under SLIME's control. 
:FD-HANDLER
This style uses the classical Unix-style “select()-loop.” Swank registers the communication socket with an event-dispatching framework (such as SERVE-EVENT in CMUCL and SBCL) and receives a callback when data is available. In this style requests from Emacs are only detected and processed when Lisp enters the event-loop. This style is simple and predictable. 
:SIGIO
This style uses signal-driven I/O with a SIGIO signal handler. Lisp receives requests from Emacs along with a signal, causing it to interrupt whatever it is doing to serve the request. This style has the advantage of responsiveness, since Emacs can perform operations in Lisp even while it is busy doing other things. It also allows Emacs to issue requests concurrently, e.g. to send one long-running request (like compilation) and then interrupt that with several short requests before it completes. The disadvantages are that it may conflict with other uses of SIGIO by Lisp code, and it may cause untold havoc by interrupting Lisp at an awkward moment. 
:SPAWN
This style uses multiprocessing support in the Lisp system to execute each request in a separate thread. This style has similar properties to :SIGIO, but it does not use signals and all requests issued by Emacs can be executed in parallel.

The default request handling style is chosen according to the capabilities of your Lisp system. The general order of preference is :SPAWN, then :SIGIO, then :FD-HANDLER, with NIL as a last resort. You can check the default style by calling SWANK-BACKEND::PREFERRED-COMMUNICATION-STYLE. You can also override the default by setting SWANK:*COMMUNICATION-STYLE* in your Swank init file.



lithp - 22.10.2011 19:37
[#] Ответ на комментарий от lithp 22.10.2011 19:37
Вопрос не такой праздный. Например, вот берем cl-mysql  - она заворачивает запрос в список, если таблица очень большая, то slime валится.

не пользовал, но может просто пофиксить cl-mysql?
lithp - 22.10.2011 19:38
[#] Ответ на комментарий от lithp 22.10.2011 19:38
 если таблица очень большая

брать порциями?
lithp - 22.10.2011 19:42
[#] Ответ на комментарий от juna 22.10.2011 19:27
> если таблица очень большая, то slime валится.

Стэк то здесь при чём? Да и вообще, большой таблицей можно завалить всё, что угодно. Поэтому так не делают.
archimag - 22.10.2011 20:28
[#] Ответ на комментарий от archimag 22.10.2011 20:28
>Стэк то здесь при чём? Да и вообще, большой таблицей можно завалить всё, что угодно.
Во-первых, стек здесь ровно при том, как и в задаче с большим списком из случайных чисел - таблица заворачивается в список. Во-вторых, cl-mysql  - это для примера (в нем, по-моему, можно как советует lithp, брать порциями).
Сформулируем так: есть функция, которая принимает на вход список (списки), а потом как с единым целым с ним (ними) работает. Например, быстрая сортировка:

(defun DevisionS1 (a L) 
  (cond
    ((Null L) nil)
    ((> a (car L)) (cons (car L) (DevisionS1 a (cdr L))))
    (t (DevisionS1 a (cdr L)))))
      
(defun DevisionS2 (a L) 
  (cond
    ((Null L) nil)
    ((<= a (car L)) (cons (car L) (DevisionS2 a (cdr L))))
    (t (DevisionS2 a (cdr L)))))

(defun SortShort (L)
  (cond
    ((Null L) nil)
    (t (append (SortShort (DevisionS1 (car L) (cdr L))) 
	       (list (car L))
	       (SortShort (DevisionS2 (car L) (cdr L)))))))

(defun GenRandom (N M)
  (if (> N 0) 
      (cons (random M) (GenRandom (- N 1) M))
      nil))
В итоге нужно сделать

(SortShort (GenRandom 1000000 1000000))
Ну и что теперь - по частям его в slime сортировать? Это опять же пример, но демонстрирующий, что проблема имеет место быть.

 
juna - 22.10.2011 21:38
[#] Ответ на комментарий от juna 22.10.2011 21:38
> Во-первых, стек здесь ровно при том, как и в задаче с большим списком 
> из случайных чисел - таблица заворачивается в список.

Список размещается в куче, так что стэк здесь не при чём. Размер стэка может иметь значение при работе с большими списками только если используется рекурсивная обработка и не срабатывает оптимизация хвостовой рекурсии. В стандарте Common Lisp оптимизации хвостовой рекурсии нет, хотя некоторые реализации её и предоставляют, но тут возможны ньюансы, поскольку это всего лишь оптимизация (а не жёсткое требование стандарта как в scheme). Поэтому, обработку больших списков на CL лучше  делать без использования рекурсии.
archimag - 22.10.2011 22:49
[#] Ответ на комментарий от archimag 22.10.2011 22:49
to archimag

Если я его ввожу руками, то да.
Посмотрите, в моей задаче прежде чем список появится в куче, он должен быть порожден в стеке, хвостовая рекурсия в котором невозможна по причине, что нечего аккумулировать - порождается сам список. Так что в этой задаче нужно регулировать именно размер стека. Да и вообще, если оптимизация хвостовой рекурсии возможна, ее и руками легко делать без всяких ньюансов, поэтому никаких принципиальных проблем для больших списков, по сравнению с небольшими в CL быть не должно.
juna - 22.10.2011 23:09
[#] Ответ на комментарий от juna 22.10.2011 23:09
В подобной ситуации лучше использовать loop.
LinkFly - 24.10.2011 17:28
[#] Ответ на комментарий от LinkFly 24.10.2011 17:28
Что-то типа:

(let ((N 0) (f nil) (K 1000000) (M 1000))
  (loop
     (if (> N K) (return f))
     (setf f (cons (random M) f))
     (setf N (1+ N))))

так 1. без  побочных эффектов не получится; 2. при К в 10 раз больше указанного нужно уже default размер кучи менять; 3. существенно переделывать рекурсивные алгоритмы.

juna - 25.10.2011 20:43
[#] Ответ на комментарий от juna 25.10.2011 20:43
1. В чём проблема? Задаётся же локальный контекст в let, можно и в loop локальные переменные объявить, так что считай без побочных эффектов.
2. Ну надо, значит надо. Ну если не хватает памяти для данных, значит надо память увеличить. Я так понял в SBCL задаётся соотв. лимит?
3. Ну смотря сколько алгоритмов. Использовать loop зачастую удобнее, я имею в виду не эту, а длинную форму.
LinkFly - 25.10.2011 21:33
[#] Ответ на комментарий от juna 25.10.2011 20:43
(loop
  for N from 0 below 1000000

  if (> N K) do (return result)
LinkFly - 25.10.2011 21:35
[#] Ответ на комментарий от juna 25.10.2011 20:43
Вот так будет правильно:

(loop
        for N from 0 below 1000000
        collect (random 1000))
LinkFly - 25.10.2011 21:38
[#] Ответ на комментарий от LinkFly 25.10.2011 21:38
Ну или если переворачивать список не надо:

(loop
        for N from 0 below 1000000
        for result = nil then (cons (random 1000) result)
        finally (return result))
LinkFly - 25.10.2011 21:43
[#] Ответ на комментарий от LinkFly 25.10.2011 21:43
> В чём проблема? Задаётся же локальный контекст в let, можно и в loop локальные переменные объявить, так что считай без побочных эффектов.
В моем коде побочные эффекты есть внутри контекста.

>Я так понял в SBCL задаётся соотв. лимит?
Да, можно
sbcl --dynamic-space-size 1000

>Ну смотря сколько алгоритмов.
Да хотя бы алгоритм быстрой сортировки переделать. :) Конечно, для примера, но  все же.

Это я к тому - стоят ли затраты на это переделывание, одного единственного действия - увеличить объем стека для рекурсивных вызовов?

 

juna - 25.10.2011 22:58
[#] Ответ на комментарий от juna 25.10.2011 22:58
> sbcl --dynamic-space-size 1000

Это ограничит максимальный размер кучи. Обычно размер кучи не надо задавать специально, она увеличивается автоматически.

> Да хотя бы алгоритм быстрой сортировки переделать. :) 

Зачем он вообще нужен, если есть стандартный sort ?

> стоят ли затраты на это переделывание, одного единственного действия - увеличить объем стека для рекурсивных вызовов?

В функциональных языках используются специальные реализации стэка, которые позволяют избегать таких проблем, да и оптимизация "tail call" гарантированно работает. Но CL не является функциональным языком (а только имеют ограниченную поддержку функциональной парадигмы). Поэтому вообще не стоит писать подобный код на CL. Возьмите лучше Scheme или там Haskell наконец.

> увеличить объем стека для рекурсивных вызовов?

Стэк размеров в 1 Гб? Вы вообще хотя бы примерно представляете последствия? А добавьте в свой вызов ещё один нолик и его перестанет хватать.
archimag - 25.10.2011 23:40
[#] Ответ на комментарий от archimag 25.10.2011 23:40
Давайте поэкспериментируем:

>sbcl
* (let ((N 0) (f nil) (K 100000000) (M 1000))
  (loop
     (if (> N K) (return f))
     (setf f (cons (random M) f))
     (setf N (1+ N))))
...
Total bytes allocated    = 536762888
   Dynamic-space-size bytes = 536870912
GC control variables:
   *GC-INHIBIT* = true
   *GC-PENDING* = in progress
   *STOP-FOR-GC-PENDING* = false
fatal error encountered in SBCL pid 3652(tid 3085067968):
Heap exhausted, game over.

>sbcl --dynamic-space-size 2000
* (let ((N 0) (f nil) (K 100000000) (M 1000))
  (loop
     (if (> N K) (return f))
     (setf f (cons (random M) f))
     (setf N (1+ N))))
работает
Так что надеяться на автоматику ненадежно.

>Зачем он вообще нужен, если есть стандартный sort ?
Не воспринимайте все буквально. Конечно, sort есть, но даже в этом случае легко может потребоваться свой алгоритм сортировки - для сортировки текста.

> В функциональных языках используются специальные реализации стэка, которые позволяют избегать таких проблем.
Что за специальные реализации стека?
> Но CL не является функциональным языком (а только имеют ограниченную поддержку функциональной парадигмы)
Какие именно ограничения?
juna - 26.10.2011 00:23
[#] Ответ на комментарий от juna 26.10.2011 00:23
Вы будете смеяться, но...

(setq slime-lisp-implementations
      `((sbcl ("/home/user/sbcl") :coding-system utf-8-unix)))


cat /home/user/sbcl
#!/bin/sh
sbcl --dynamic-space-size 500


*nix-way однака
ted - 02.12.2011 12:23
[#] Ответ на комментарий от ted 02.12.2011 12:23
Разврат, конечно, но спасибо! ;-)
juna - 02.12.2011 14:53
@2009-2013 lisper.ru