按原样重新编译 CL 系统 运行

Recompiling a CL system as it is running

我是运行一个普通的lisp项目,每5秒获取一次市场数据。我对代码做了一些调整,想在生产环境中更新它。事件循环真的很标准:

(loop
   (fetch-data)
   (sleep 5))

由于 loop 的阻塞特性,我无法使用 REPL。

我的问题:我可以动态更新 运行 代码吗?

我知道我可以用 (asdf:compile-system :system-name)

重新编译项目

我也知道我可以redefine classes at runtime。 (并不是说我在我的实现中使用 类)

但是现在我不能使用 REPL,我必须以某种方式将环境加载到另一个 REPL 中。有没有办法做到这一点? (我正在使用 SBCL)

在我看来,最简洁的方法就是实现异步数据获取。

Because of the blocking nature of the loop I don't have the REPL at my disposal.

有很多解决方法:

  • 自己开始循环 thread
  • 或者在你的 Lisp
  • 中连接类似 SLIME to a running SWANK 的东西
  • 或者您的循环可以定期检查代码更新

我也不会编译程序内部的代码,除非您知道代码确实可以编译或者您可以处理编译错误。编译和加载通常也比加载慢。

请注意,将代码加载到 运行ning 程序中并未标准化。使用 SBCL,您不仅可以拥有线程,而且线程可能 运行 并发。有一些更改可能不是线程安全的,或者会导致 运行ning 程序出现问题。因此,您需要计划好要进行的更改。

有一点可以简化更改代码:在循环休眠时加载更新,如果可以在 5 秒内加载更新 window。

一些程序可能需要更多的架构,比如在更新这些部分时关闭部分程序的能力。

不确定这是否适用于您的情况,但我已经非常成功地使用 swank::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")))))

restart-case 构造允许在出现错误时不中断循环,并在错误得到修复后继续循环。

我不确定这种方法是否可靠,AFAIK swank 默认使用线程处理请求,因此可能存在一些同步问题,因此可能不适用于生产用途,用于开发/调试。

据我所知CEPL uses something similar, may be more sophisticated and robust version. Also nice CEPL demo video.