在“运行时”编辑程序?为什么?

时间:2011-02-22 06:24:29

标签: clojure lisp scheme

我最近越来越多地使用Lisp和Lispy语言,而且我发现它们非常强大。

我在网上阅读的一件事是,在Lisp,Clojure等中写作的好处是你可以“在它运行时”编辑你的程序。

也许我错过了什么,但有什么意义呢?

当然,它可能会节省几秒钟,但就是这样吗?每当我对我的程序进行更改时,我就会停止它,然后重新启动它,这已经好几十年了。

除了节省时间之外,还有其他原因 - 它是什么?

有人可以给我一个很好的案例研究,让我对这个功能流口水吗? :)

期待流口水!

13 个答案:

答案 0 :(得分:57)

  

除了节省时间之外,还有其他原因 - 它是什么?

不,没有。我的意思是,永远不会完整的理由使用计算机就是为了节省时间。没有什么是电脑无法用手做的。这需要更长的时间。

在这种情况下,我不会忽视“几秒钟”,因为这是我整个编程生涯中一天比其他任何事情都要做的事情之一。几秒钟重新编译,几秒钟重新运行,几秒钟重新创建我的程序前一次的状态 - 即使在快速工作站上,迭代之间也很容易。 (它曾经更糟糕,但更快的硬件只会使它变得不那么糟糕,不好。整个文件或更糟的重新编译是I / O绑定的,并且可能永远*不匹配更细粒度编译的速度。)

在Lisp中,在已经运行的进程中重新编译单个函数几乎是即时的(即使在我5岁的笔记本电脑上,我也从未见过它甚至0.1秒),重启意味着我没有必要重建我的状态,即使有什么信号。

这是一个工具,可以让我超过100倍的速度,这是我作为程序员所做的最慢和最常见的事情之一。我不知道你还需要什么。我们可以弥补一些原因,但如果这不够理由,我不知道会是什么。嗯,这也很酷? : - )

(*每当有人说“从不”涉及技术的事情时,那个人总是在2年后看起来像一个完整的白痴,尽管Lisp的长寿,我肯定也不例外。)

答案 1 :(得分:56)

有一些非常酷的用例。一个例子是GUI编程 - 我在Emacs旁边运行时实时开发GUI应用程序时看到了这一点:我添加了一个新按钮的代码并点击“Cc Cc”来编译该单个函数,而按钮只是< em>在窗口出现!没有关闭并重新打开应用程序。然后我开始调整小部件并操纵布局,打开的窗口会立即重新排列 - 按钮会四处移动,新的文本字段会在我执行每一个小改动后立即生成等等。

另一个例子是关于Clojure OpenGL库“Penumbra”的优秀截屏视频,程序员可以实时创建3D俄罗斯方块游戏。他从他的emacs旁边的一个空的OpenGL窗口开始。他定义了一个立方体对象 - C-M-x - 它就在屏幕上。运行命令旋转它,立即开始旋转。运行一个循环,在不同的位置定义另外5个立方体,它们会出现pop-pop-pop-pop-pop。这一切都立即响应,完整的OpenGL工具包就在那里玩。向立方体添加新的曲面纹理,并立即看到它。它变成了一个可塑性的3D世界 - 代码动态地修改现有世界,而不是每次更改都关闭并重新打开3d画布。

Penumbra Livecoding Screencast - 下载高清版本以获得最佳体验。

还有关于Clojure的音频库“Overtone”的精彩演示/截屏。该库是一个合成器工具包,您可以在其中使用一组合成函数来操纵声波。在演示期间,开发人员编写了一些启动音调播放的代码。然后他花了十秒钟写了一个循环,播放了10次这个声音,但每次都让频率更高,再次C-M-x,你听到它,音符越来越高。在20分钟的实时空间里,他得到了一首歌。看起来很有趣。

Overtone Presentation Link

其他用途是,例如:Web爬行/数据挖掘 - 开发和改进用于实时提取信息的算法,查看每一步返回的数据;机器人编程 - 在机器人生存时发送命令;面部/图像识别 - 使用像OpenCV这样的库观察您的更改会在您开发代码时立即更新库在图像/视频中识别的内容;数学工作(Clojure有“Incanter”统计数据);以及您希望立即查看更改对您正在使用的数据产生的影响的任何环境。

所以这是在你面前拥有REPL最有趣的方面。那些没有实际,可塑性,互动性的东西开始成为现实。 GUI设计,3D图形,程序化声音制作,数据提取和转换,这些事情通常都是在公平的情况下完成的。但是对于Clojure(在某种程度上还有其他动态语言),它是真正有形和直接的;你在编写代码时就会看到每个变化,如果某些东西不起作用或者你没有得到你期望的结果,你只需改变你错过的东西并立即重新执行。

Clojure非常注重这样做。野蛮的是你可以以同样的方式实时使用Java库 - 尽管Java本身不能!因此,Overtone实时使用Java合成库,尽管你从未在Java中使用,Penumbra正在使用Java OpenGL绑定等。这是因为Rich Hickey设计了Clojure,因此可以动态编译为JVM字节码。这是一种令人惊叹的语言 - Clojure为编程带来了极其有趣和高效的贡献。

答案 2 :(得分:27)

Lisp有一个营销口号:

使用Lisp及其增量开发方法,更改软件系统的成本取决于更改的大小,而不是整个软件的大小。

即使我们拥有庞大的软件系统,变更的成本(时间......)仍然与变更的大小有关。如果我们添加一个新方法或更改一个新方法,那么努力仍然与编辑方法的工作有关,逐步编译方法并逐步加载方法。

在许多传统软件环境中,方法的更改可能需要部分重新编译,新的链接可执行文件,重新启动,重新加载等。软件越大,所需的时间就越长。

对于人来说,这意味着,我们可能会超出流量状态。这是良好的Lisp环境生产力的一部分:一旦程序员感到舒适并进入流程状态,就可以在短时间内对软件系统进行大量更改。我想很多人都经历过这种情况,即工作在短时间内完成 - 与一个人坐在一个没有反应的系统前面并且我们面临等待时间的时间相反。

我们和我们正在制作的计划之间也没有认知距离。 例如,如果在批处理环境中编辑类,则必须想象更改所具有的效果。在Lisp中,您可以编辑一个类并同时更改对象本身。这意味着您可以直接更改对象的行为 - 而不是批量编辑 - 编译 - 链接 - 运行 - 测试周期后的新版本。

在Lisp系统中,您可以更改CAD系统中的类,然后可以立即激活它。 当人们问,如果Lisp适用于大型软件团队,那么答案可能是大型软件团队没有必要,如果你以增量方式工作。那么问题是熟悉增量开发的真正优秀的熟练软件开发人员(很少见)。

在许多应用程序中,有一个单独的脚本语言层,有时用于原始开发人员(而不是用户)。在Lisp中,这不是必需的, Lisp是它自己的扩展语言

答案 3 :(得分:21)

在现实世界中,这主要用于开发,就像许多功能一样,它在正确的环境中值得流口水。

  1. 个人程序员启蒙幸福*
  2. 真正的持续部署。
  3. 零计划停机服务水平协议。
  4. 调试生产服务器。
  5. *不是保证。

    <小时/> 对我来说,我怀疑其他人在这里 REPL驱动的开发的真正好处是它可以难以形容的有趣。上瘾甚至。它有时真的可以给人一种制作代码的感觉。尝试一下...来吧男人试一试,首先REPL总是免费的:)

    <小时/> 这些天的一大吸引力是持续部署。

    目前持续部署的想法是你改变一件事,构建所有东西(或者包装它)然后进行部署。使用lisp模型,它实际上可以在部署时编辑已部署的(通常是收到真实客户会话镜像的框)框。

    只是一个迂腐的笔记。你真的不编辑正在运行的类。您编译该类的新副本并将其保留在已知位置(var),然后在下次使用时找到并使用新副本。它不是在运行时编辑而更像是新代码立即生效这减少了从程序到表达式(通常是函数)的开发过程的范围。

    <小时/> 另一个流口水的想法是获得安全修复的好处而不必声明任何停机时间。你可以进行升级而不用花费你的SLA任何宝贵的“计划停机时间”。如果你必须提前六个月安排计划停工时间,那么你只需要两个小时的时间(对于这些可怜的灵魂)它可能会让他们流口水。
    如果您在部署时(可能(有权限)在客户站点上拥有对正在运行的应用程序的repl访问权限),您可以在应用程序运行时连接到该应用程序,并在现有上下文中对现有代码运行测试不必停止并连接调试器。你也不会从调试器中获得任何速度损失。可以在没有REPL的情况下执行此操作,但是当您在那里获得repl时,您可以轻松地创建新代码(有些人会说通过调试器注入动态类加载器很容易),然后解决问题。所以你可以连接到正在运行的服务器。发现一个函数在短暂停机后无法重新连接到数据库,然后在那里重新连接。

    <小时/> 与所有编程结构一样,永远不会成为银弹并且这种持续的部署/开发有一个有趣的缺点:你的程序在内存中是正确的,在磁盘上是错误的。如果你编译一个函数然后打破它并保存,那么代码的唯一工作副本就是运行的那个。保存后立即知道这个并重新评估文件是没有用的。
    这可能听起来很奇怪,所以去结账如何Embed a Clojure REPL in your production application

答案 4 :(得分:14)

我记得来自美国宇航局的人描述了他的经历。他的团队在70年代实施了用于宇宙飞船的软件。当发现一些错误时,他们有效地远程修改了它们的软件。

或者想象你有一个漫长的过程需要几天才能执行,最后由于权限或其他小问题而无法写入结果。

又一个例子。您处于集成阶段,您必须进行许多小的更改。而且他们中的很多人。我在Java中实现了这种可能性,因为目前我需要30-40分钟才能重建并重新安装我的应用程序(在10分钟内重新生成它)。

答案 5 :(得分:9)

如果你看一下像Erlang这样的东西,关键是要避免停工。

它可以在手机开关之类的东西上运行,你不能只关闭几秒钟。

对于更常见的用途,它是一个“很好的”功能,但是,可能并不重要。

答案 6 :(得分:5)

您会看到真实的数据。这是一个很大的优势。然后你不必推测。

答案 7 :(得分:5)

因为你可以吗?

说真的,只是尝试一下,当你回到没有REPL的旧编程语言时,你会感到痛苦。

即时反馈,轻松快速进行测试,无需在测试夹具中设置虚假程序状态,能够检查正在运行的程序的状态(该变量的值是多少)。所有这些都是实时储户。

答案 8 :(得分:3)

这主要是为了开发,它只是节省时间。

但节省时间非常重要。

一旦你习惯了,它就会回到古老的方式,感觉就像从飞行到焦油游泳。

答案 9 :(得分:2)

在工业系统中,它用于PLC编程,以减少停机时间和不安全状况。

这些系统用于核电站,制造系统,钢铁厂等。该过程始终持续运行,停机时间非常昂贵或不安全。想象一下,一个控制核反应堆冷却的系统,你无法关闭该系统来部署新代码,你必须能够在它运行时对其进行修改。

这类似于电话交换机系统的Erlang答案。

答案 10 :(得分:1)

好吧,想象一下你需要修补服务器而停止它。

如果你用“典型”语言这样做,那将会涉及一些重要的魔法。你必须在执行代码后面“后面”。我认为它需要修补函数表等等,所有这些都在汇编和操作指向函数的指针。错误的好地方。

在Lisp中,没有停机时更新的想法已内置于语言模型中。虽然有一些更新的复杂性,你无法摆脱(如何处理长时间运行的连接),它不需要编译语言的重大魔力。

虽然我没有花费大量时间(即任何有用的东西),但我确实在Common Lisp中编写了一个服务器原型,它至少可以通过网络进行某些实时修补停机时间。

答案 11 :(得分:0)

另外一件好事,除了在不重新启动所有内容的情况下即时修改程序(已经完成了几十年并不意味着它是最好的,对吧?),是你要检查你的程序它目前的状态,能够弄清楚发生了什么。

答案 12 :(得分:0)

Casey Muratori刚刚用C和Microsoft的C / C ++编译器做了一些关于如何做到这一点的课程。它实际上很简单,只有几十行代码。观看视频22/24/25:

https://www.youtube.com/watch?v=WMSBRk5WG58

在游戏设计中,理由是能够更快地调整常数以找到您的目标情感。游戏感觉,非玩家行为脚本和装饰照明/氛围等因素从中受益匪浅。