我正在运行一个常见的lisp项目,每5秒获取一次市场数据。我对代码做了一些调整,并希望在生产环境中更新它。事件循环非常标准:
(loop
(fetch-data)
(sleep 5))
由于loop
的阻塞性质,我没有掌握REPL。
我的问题:我可以动态更新正在运行的代码吗?
我知道我可以使用(asdf:compile-system :system-name)
我也知道我可以redefine classes at runtime。 (不是我在我的实现中使用类)
但是现在我不能使用REPL我必须以某种方式在另一个REPL中加载环境。有没有办法做到这一点? (我正在使用SBCL)
在我看来,最干净的方法是实现异步数据提取。
答案 0 :(得分:3)
由于循环的阻塞性质,我没有可供使用的REPL。
有各种方法:
我也不会编译程序中的代码,除非你知道代码实际编译或者你可以处理编译错误。编译和加载通常也比加载慢。
请注意,将代码加载到正在运行的程序中并不是标准化的。使用SBCL,您不仅可以拥有线程,而且线程可以同时运行。有些更改可能不是线程安全的,或者在正在运行的程序中导致问题。因此,您需要计划您想要做的更改。
简化更改代码的一件事:在循环休眠时加载更新,如果在5秒窗口内可以的话。
某些程序可能需要更多架构,例如在更新这些部件时关闭部分程序的能力。
答案 1 :(得分:1)
不确定这是否适用于您的情况,但我已经成功地使用swnk :: handle-request在循环中调用REPLing并使用正在运行的交互式应用程序:
(defun handle-swank-requests ()
(let ((connection (or swank::*emacs-connection*
(swank::default-connection))))
(when connection
(swank::handle-requests connection t))))
(defun main-cycle ()
(loop
(restart-case
(progn
(handle-swank-requests)
(fetch-data)
(sleep 5))
(continue () :report "Continue" (print "Continued after error from SWANK")))))
重启案例构造允许不破坏错误循环,并在错误得到修复后继续。
我不确定这种方法是否是防弹的,AFAIK swank默认使用线程进行请求处理,因此可能存在一些同步问题,因此可能不会用于生产用途,无法进行开发/调试。
AFAIK CEPL使用类似的东西,可能是更复杂和更健壮的版本。也很好CEPL demo video。