“在程序运行时”编辑程序?为什么?
最近我对 Lisp 和 Lispy 语言有了更多的了解,我发现它们非常强大。
我在网上读到的一件事是,用 Lisp、Clojure 等编写的好处是,您可以“在程序运行时”编辑程序。
也许我错过了一些东西,但这有什么意义呢?
当然,这可能会节省几秒钟,但仅此而已吗?每当我对程序进行更改时,我都会停止它然后再次启动它,几十年来一直运行良好。
除了节省时间之外,肯定还有其他原因——那是什么?
有人能给我一个很好的案例研究,让我对这个功能垂涎欲滴吗? :)
期待流口水!
I've been getting more into Lisp and Lispy languages lately, and I'm finding them quite powerful.
One thing I've been reading all over the net is that a benefit of writing in Lisp, Clojure, etc, is that you can edit your program "while it's running".
Perhaps I'm missing something, but what is the point?
Sure, it might save a few seconds, but is that all? Whenever I make a change to my program I just stop it then start it again, and that has been working fine for decades.
There must be a reason other than just saving time -- what is it?
Can someone give me a good case study that will make me drool over this feature? :)
Looking forward to drooling!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(13)
有一些非常酷的用例。一个例子是 GUI 编程 - 我在实时开发一个 GUI 应用程序时看到了这一点,因为它在我的 Emacs 旁边运行:我为一个新按钮添加了代码,然后点击“抄送抄送”来编译该单个函数,该按钮只是 < em>出现在窗口中!无需关闭并重新打开应用程序。然后我开始调整小部件并操纵布局,一旦我执行了所做的每个小更改,打开的窗口就会立即重新排列自己 - 按钮会四处移动,新的文本字段会突然出现,等等。
另一个例子是关于 Clojure OpenGL 库“Penumbra”的精彩截屏视频,其中程序员实时创建了 3D 俄罗斯方块游戏。他首先在 emacs 旁边有一个空的 OpenGL 窗口。他定义了一个立方体对象 - CMx - 并且它出现在屏幕上。运行命令来旋转它,它立即开始旋转。运行一个循环,在不同位置定义另外 5 个立方体,它们会出现 pop-pop-pop-pop-pop。一切都是立即响应的,完整的 OpenGL 工具包就在那里可以使用。向您的立方体添加新的表面纹理,然后立即看到它出现。它变成了一个可延展的 3D 世界 - 代码动态修改现有世界,而不是在每次更改时关闭并重新打开 3D 画布。
Penumbra Livecoding Screencast - 下载高清版本以获得最佳体验。
还有一个关于 Clojure 音频库“Overtone”的精彩演示/截屏视频。该库是一个合成器工具包,其中有一组合成器函数来操纵声波。在演示过程中,开发人员编写了一些开始播放提示音的代码。然后,他花了 10 秒钟编写一个循环,播放该声音 10 次,但每次都会使频率更高,然后再次 CMx,您会听到它,音符上升更高。在 20 分钟的时间内,他实时演唱了一首歌。看起来很有趣。
泛音演示链接
其他用途包括:网络爬行/数据挖掘 - 开发和完善用于提取信息的算法实时,查看每一步返回的数据;机器人编程——在机器人运行时向机器人发送命令;面部/图像识别 - 使用 OpenCV 这样的库,在您开发代码时,可以立即观察您的更改,更新库在图像/视频中识别的内容;数学工作(Clojure 有用于统计的“Incanter”);以及您想要立即查看更改对正在使用的数据产生的影响的任何环境。
所以这就是 REPL 在你面前最有趣的方面。那些无形的、可塑的、互动的东西开始变得有形。 GUI 设计、3D 图形、程序化声音制作、数据提取和转换,这些事情通常都是在一定距离内完成的。但对于 Clojure(在某种程度上,其他动态语言也是如此),它变得真正有形且即时;一旦编写代码,您就会看到每个更改,如果某些内容不起作用或没有得到预期的结果,您只需更改错过的内容并立即重新执行即可。
Clojure 非常愿意这样做。疯狂的是,您可以以同样的方式实时使用 Java 库 - 尽管 Java 本身不能!因此,Overtone 正在实时使用 Java 合成库,尽管事实上在 Java 中永远无法做到这一点,Penumbra 正在使用 Java OpenGL 绑定等。这是因为 Rich Hickey 设计了 Clojure,因此它可以动态编译为 JVM 字节码。这是一门令人惊叹的语言 - Clojure 为编程变得如此有趣和高效做出了巨大贡献。
There are some extremely cool use cases. One example is in GUI programming - I saw this while developing a GUI app in real time as it was running beside my Emacs: I added code for a new button and hit "C-c C-c" to compile that single function, and the button just appeared in the window! Didn't have to close and reopen the app. Then I began tweaking widgets and manipulating the layout, and the open window would instantly rearrange itself - buttons would move around, new text fields would just pop into being, etc. as soon as I executed each little change I'd made.
Another example is an excellent screencast about the Clojure OpenGL library "Penumbra" where the programmer creates a 3D tetris game in real time. He starts with an empty OpenGL window next to his emacs. He defines a cube object - C-M-x - and it's on the screen. Runs a command to rotate it, immediately it starts spinning. Runs a loop defining 5 more cubes in different locations, pop-pop-pop-pop-pop they appear. It's all immediately responsive, the full OpenGL toolkit right there to play with. Add a new surface texture to your cube and see it appear right away. It becomes a malleable 3d world - the code dynamically modifies the existing world instead of closing and reopening the 3d canvas with every change.
Penumbra Livecoding Screencast - download HD version for best experience.
There is also a great presentation/screencast about the audio library "Overtone" for Clojure. The library is a synthesizer toolkit where you have a set of synth functions to manipulate the soundwave. During the presentation, the developer writes a bit of code that starts a tone playing. He then spends ten seconds writing a loop that plays that sound 10 times but makes the frequency higher each time, and again C-M-x and you hear it, notes ascending higher. Over the space of 20 minutes in real time he gets a song going. It looks like a ton of fun.
Overtone Presentation Link
Other uses would be, for example: Web crawling/data mining - develop and refine algorithms for extracting information in real time, seeing the data returned at each step; Robotics programming - send commands to a robot while it's live; Facial/image recognition - with a library like OpenCV watch your changes instantly update what the library recognizes in an image/video as you're developing the code; Mathematics work (Clojure has "Incanter" for statistics); and any environment where you want to immediately see what effect your changes have had on the data you're working with.
So that's the most fun aspect of having a REPL in front of you. Things that weren't tangible, malleable, interactive, start to be. GUI design, 3D graphics, programmatic sound production, extracting and transforming data, these things normally have been done at arm's length. But with Clojure (and to some extent with other dynamic languages too) it's made to be really tangible and immediate; you see each change as soon as you write the code, and if something doesn't work or you don't get back the result you expected, you just change what you missed and re-execute it immediately.
Clojure is very aligned towards doing this. The wild thing is you can use Java libraries in real-time the same way - despite the fact that Java itself can't! So Overtone is using a Java synth library in realtime despite the fact you never could in Java, Penumbra is using the Java OpenGL bindings, etc. This is because Rich Hickey designed Clojure so it could compile to JVM bytecode on the fly. It's an amazing language - Clojure has made a huge contribution to how incredibly fun and productive programming can be.
不,没有。我的意思是,从来是:使用计算机的全部原因就是为了节省时间。没有什么是电脑能做但手工做不到的。只是需要更长的时间。
在这种情况下,我不会忽略“几秒钟”,因为这是我在整个编程生涯中整天最常做的事情之一。几秒钟重新编译,几秒钟重新运行,几秒钟重新创建程序上次的状态——即使在快速工作站上,迭代之间也很容易需要一分钟。 (过去情况要糟糕得多,但更快的硬件只会让它变得不那么可怕,而不是更好。整个文件或更糟的重新编译是 I/O 绑定的,并且可能永远无法*匹配更精细编译的速度。)
在 Lisp 中,在已经运行的进程中重新编译单个函数几乎是瞬时的(我从来没有见过它甚至是 0.1 秒,即使是在我用了 5 年的笔记本电脑上),并且重新启动意味着我不必重新创建我的状态,即使有信号发出。
这是一个工具,它可以让我作为程序员所做的最慢且最常见的事情之一加速超过 100 倍。我不知道你还需要什么。我们也许可以编造一些理由,但如果这还不够,我不知道还会有什么理由。嗯,也很帅吧? :-)
(* 每当有人对涉及技术的事情说“决不”时,两年后,那个人总是看起来像个彻头彻尾的白痴,尽管 Lisp 很长寿,我也肯定不会例外。)
No, there isn't. I mean, there never is: the whole reason to use a computer at all is to save time. There's nothing a computer can do that you can't do by hand. It just takes a little longer.
In this case, I wouldn't dismiss "a few seconds", given that it's one of the things I do more often than anything else, all day long, for my entire programming career. A few seconds to recompile, a few seconds to re-run, several seconds to recreate the state my program had the previous time -- even on a fast workstation, it can easily be a minute between iterations. (It used to be much worse, but faster hardware has only made it less-awful, not good. Whole-file-or-worse recompiles are I/O-bound, and may never* match the speed of more granular compilation.)
In Lisp, recompiling a single function in an already-running process is almost instantaneous (I've never seen it even 0.1 sec, even on my 5-year-old laptop), and restarts mean I don't have to recreate my state, even when something signals.
Here's a tool that gives me over a 100x speedup of one of the slowest and most common things I do as a programmer. I don't know what else you'd need. We can probably make up some reasons, but if this isn't reason enough I don't know what would be. Um, it's also pretty cool? :-)
(* Whenever somebody says "never" about something involving technology, that person invariably ends up looking like a complete moron 2 years later, and despite Lisp's longevity, I am sure to be no exception.)
Lisp 有一句营销口号:
对于 Lisp 及其增量开发方法,软件系统变更的成本取决于变更的规模,而不是整个软件的规模。
即使我们有一个大型软件系统,更改的成本(时间,...)仍然与更改的大小相关。如果我们添加新方法或更改新方法,则工作量仍然与编辑方法、增量编译方法和增量加载方法的工作量有关。
在许多传统的软件环境中,方法的改变可能需要部分重新编译、新的链接可执行文件、重新启动、重新加载等。软件越大,花费的时间就越长。
对于人类来说,这意味着我们可能会脱离心流状态。这是良好 Lisp 环境生产力的一部分:一旦程序员感到舒适并进入这种流程状态,就可以在短时间内对软件系统进行大量更改。我想很多人都经历过这种情况,工作可以在短时间内完成,而不是坐在一个没有响应的系统前,我们面临着等待时间。
此外,我们和我们正在开发的项目之间的认知距离很小。
例如,如果您在批处理环境中编辑一个类,您必须想象更改所产生的效果。在 Lisp 中,你编辑一个类并同时更改对象本身。这意味着您可以直接更改对象的行为,而不是在批量编辑-编译-链接-运行-测试周期之后更改对象的新版本。
在 Lisp 系统中,您可以更改 CAD 系统中的类,然后它可以立即激活。
当人们问,Lisp 是否适用于大型软件团队时,答案可能是,如果你增量工作,大型软件团队就不是必需的。那么问题是,真正熟练、熟悉增量开发的软件开发人员很少。
在许多应用程序中,有一个单独的脚本语言层,有时是为原始开发人员(而不是用户)提供的。在 Lisp 中这不是必需的,Lisp 是它自己的扩展语言。
There is a marketing slogan for Lisp:
With Lisp, and its incremental development method, the cost for a change to a software system depends on the size of the change, and not the size of the whole software.
Even if we have a large software system, the cost (time, ...) for a change stays in relation to the size of a change. If we add a new method or change a new method, the effort remains in relation to the effort to edit the method, incrementally compile the the method and incrementally load the method.
In many traditional software environments, the change of a method may need a partial recompilation, a new linked executable, a restart, a reload, etc.. The larger the software is, the longer it takes.
For a human this means, we get possibly out of a state of flow. That's part of the productivity of good Lisp environments: one can make a lot of changes to a software system in a short time, once the programmer feels comfortable and enters this state of flow. I guess many have experienced this, where work gets done in a short time - opposed to times when one sits in front of a system which is unresponsive and we are faced with wait times.
Also there is little cognitive distance between us and the program we are working on.
For example if you edit a class in a batch environment, you have to imagine the effect the changes have. In Lisp you edit a class and change at the same time the objects themselves. That means you change the behavior of objects directly - and not a new version of them after a batch edit-compile-link-run-test cycle.
In a Lisp system, you change a class in a CAD system and then it can be immediately active.
When people ask, if Lisp works for large software teams, the answer may be that the large software team is not necessary, if you work incrementally. The problem then was/is that really good skilled software developers familiar with incremental development were (are?) rare.
In many applications there is a separate scripting language layer, sometimes for the original developers (and not for users). In Lisp this is not necessary, Lisp is its own extension language.
在现实世界中,这主要用于开发,并且像许多功能一样,它只有在正确的上下文中才值得垂涎。
*不是保证。
for me, and i suspect some others here the real benefit of this REPL driven development is that it can be indescribably fun. addictive even. It can sometimes really give a sense of crafting-code. give it a try... come on man try it out, first REPL's always free :)
one big draw these days is continual deployment.
目前持续部署的想法是改变一件事,构建所有内容(或者打包它)然后部署。使用 lisp 模型,实际上可以在部署时编辑已部署的框(通常是接收真实客户会话镜像的框)。
只是一个迂腐的注释。您实际上并不编辑正在运行的类。您编译该类的新副本并将其保留在已知位置(var),然后下次使用它时,会找到并使用新副本。它并不是真正的运行时编辑,更像是新代码立即生效,这减少了从程序到表达式(通常是函数)的开发过程的范围。
another drooling point is the idea of getting the bennefit of security fixes with out having to declare any downtime. you can do an upgrade with out it costing your SLA any of you precious "scheduled downtime". If you have to schedule planned downtime six months in advance, and you only get two hours of it then (for these poor souls) it could really make them drool.
If you have repl access to your running application as it is deployed (potentially (with permission) at a customer site) you can connect to the app while it is running and run tests on the existing code in the existing context with out having to stop and connect a debugger. you also wont get any speed loss from a debugger. It's possible to do this with out a REPL, though when you get the repl in there you can then create new code easily (some will say that injecting dynamic class loaders through the debugger is easy) and then fix things. So you could connect to a running server. discover that a function failed to re-connect to a database after a short outage and then reconnect it right then and there.
as with all programming constructs there never will be a silver bullet and this continual deployment/development has an interesting downside: you program can be correct in memory and wrong on the disk. if you compile a function then break it and save then the only working copy of the code is the one running. I't useful to be aware of this and re-eval files just after you save them.
This may sound fanciful so go checkout how to Embed a Clojure REPL in your production application
In the real world this is mainly used in development and like many features its only worth drooling over in the right context.
*not a guarantee.
for me, and i suspect some others here the real benefit of this REPL driven development is that it can be indescribably fun. addictive even. It can sometimes really give a sense of crafting-code. give it a try... come on man try it out, first REPL's always free :)
one big draw these days is continual deployment.
currently the idea for continual deployment is that you change one thing, build everything (or package it rather) then deploy. with the lisp model its actually possible to edit a deployed (usually a box that is recieving a mirror of real customer sessions) box while it is in deployment.
just a pedantic note. you dont actually edit running classes. you compile a new copy of the class and leave it in a known location (a var) then the next time it is used the new copy is found and used. its not really editing while running and more like new code takes effect immediately this reduces the scope of the devlopment process from programs to expressions (typically functions).
another drooling point is the idea of getting the bennefit of security fixes with out having to declare any downtime. you can do an upgrade with out it costing your SLA any of you precious "scheduled downtime". If you have to schedule planned downtime six months in advance, and you only get two hours of it then (for these poor souls) it could really make them drool.
If you have repl access to your running application as it is deployed (potentially (with permission) at a customer site) you can connect to the app while it is running and run tests on the existing code in the existing context with out having to stop and connect a debugger. you also wont get any speed loss from a debugger. It's possible to do this with out a REPL, though when you get the repl in there you can then create new code easily (some will say that injecting dynamic class loaders through the debugger is easy) and then fix things. So you could connect to a running server. discover that a function failed to re-connect to a database after a short outage and then reconnect it right then and there.
as with all programming constructs there never will be a silver bullet and this continual deployment/development has an interesting downside: you program can be correct in memory and wrong on the disk. if you compile a function then break it and save then the only working copy of the code is the one running. I't useful to be aware of this and re-eval files just after you save them.
This may sound fanciful so go checkout how to Embed a Clojure REPL in your production application
我记得美国宇航局的某人描述了他的经历。他的团队在 70 年代实现了在宇宙飞船中使用的软件。当发现一些错误时,他们有效地远程修改了他们的软件。
或者想象一下,您有一个很长的过程需要几天的时间才能执行,最后由于权限或其他小问题而无法写入结果。
还有一个例子。你正处于整合阶段,你必须做出很多小的改变。又是很多。我梦想在 Java 中实现这种可能性,因为目前我需要 30-40 分钟来重建和重新安装我的应用程序(在 10 分钟内再次重建它)。
I remember somebody from NASA described his experience. His team implemented the soft used in a spaceship back in the 70s. And they effectively modified their soft remotely on the fly when some bugs were found.
Or imagine you have a long process taking days to execute and at the end it cannot write results because of permissions or other small problem.
Yet another example. You are in the integration phase and you have to make a lot of small changes. And again a lot of them. I dream about such a possibility in Java because currently it takes me 30-40 min to rebuild and reinstall my application (to rebuild it again in 10 min).
如果你看看像 Erlang 这样的东西,重点是避免停机。
它运行在电话开关之类的东西上,你不能只是关闭几秒钟。
不过,对于更正常的用途来说,这是一个“很好有”的功能,但是,是的,可能并不重要。
If you look at something like Erlang, the point is to avoid down time.
It runs on stuff like phone switches that you can't just turn off for a few seconds.
For more normal uses, though, it's a "nice to have" feature, but yeah, probably not critical.
你看到的是真实的数据。这是一个很大的优势。那么你就不必猜测了。
You see real data. That is a big advantage. You then don't have to speculate.
因为你可以?
说真的,只要尝试一下,当你回到没有 REPL 的旧编程语言时,你就会感到痛苦。
即时反馈,轻松进行快速测试,无需在测试装置中设置虚假程序状态,能够检查正在运行的程序的状态(该变量的值是多少)。所有这些都可以真正节省时间。
Because you can?
Seriously, just try it out for while, and you will feel the pain when you come back to your old programming language without REPL.
Instant feedback, easy making quick tests without having to set-up a fake program state in your test fixture, Ability to inspect state of running program (what is the value of that variable). All of these are a real time savers.
它主要用于开发,只是节省时间。
但节省时间却极其重要。
一旦你习惯了,回到原来的方式感觉就像从飞行变成在焦油中游泳。
It's mostly for development, where it's just a time saver.
But time savers are staggeringly important.
Once you're used to it going back to the old way feels like going from flying to swimming in tar.
在工业系统中,这用于 PLC 编程,以减少停机时间和不安全情况。
这些系统用于核电站、制造系统、钢厂等。该过程始终持续运行,停机时间非常昂贵或不安全。想象一个控制核反应堆冷却的系统,您无法关闭该系统来部署新代码,您必须能够在它运行时对其进行修改。
这类似于 Erlang 对电话交换系统的回答。
In industrial systems this is used for PLC programming to alleviate downtime and unsafe conditions.
These are systems that are used on nuclear power plants, manufacturing systems, steel mills, etc. The process is always running, continuously, and down time is very expensive or unsafe. Imagine a system that is controlling the cooling of a nuclear reactor, you cannot turn that system off to deploy new code, you must be able to modify it as it is running.
This is similar to the Erlang answer for phone switch systems.
好吧,想象一下您需要修补服务器并且不停止它。
如果您使用“典型”语言执行此操作,则将涉及一些重要的魔法。您必须在执行代码的“后面”进行搜索。我认为这需要修补函数表等,所有这些都在汇编和操作函数指针时进行。虫子的好地方。
在 Lisp 中,无需停机即可更新的理念已内置于语言模型中。虽然存在一些您无法摆脱的更新复杂性(如何处理长时间运行的连接),但它不需要编译语言的强大魔力。
尽管我没有花费大量时间(即任何有用的东西),但我确实用 Common Lisp 设计了一个服务器原型,它至少可以通过网络进行一些实时修补,而无需停机。
Well, imagine you need to patch a server and not stop it.
If you do this in a "typical" language, that's going to involve some heavy magic. You have to grub around 'behind' the executing code. I think it'd require patching the function tables and so forth, all in assembly and manipulating the pointers to functions. A good place for bugs.
In Lisp, the idea of updating without downtime is built into the language model. While there are some update complexities you can't get away from (how do you handle a long-running connection), it doesn't require the heavy magic of a compiled language.
Although I haven't spent significant time on it (ie anything useful), I did work out a prototype of a server in Common Lisp that would do at least some live patching over a network without downtime.
除了即时修改程序而无需重新启动所有内容(已经这样做了几十年并不意味着它是最好的事情,对吧?)之外,另一件好事是您可以检查程序的当前状态并进行检查。能够弄清楚发生了什么事。
Another good thing apart from modifying the program on the fly without having to restart everything (having done it for decades doesn't mean it is the best thing, right?), is that you get to inspect your program in its current state and being able to figure out what's going on.
Casey Muratori 刚刚上了一些关于如何使用 C 和 Microsoft 的 C/C++ 编译器执行此操作的课程。其实很简单,就几十行代码。查看 25 年 22 月 24 日的视频:
https://www.youtube.com/watch?v= WMSBRk5WG58
在游戏设计中,其基本原理是能够更快地调整常数以找到您想要的情感基调。游戏感觉、非玩家行为脚本和布景照明/氛围等都从中受益匪浅。
Casey Muratori just did a few lessons on how to do this with C and Microsoft's C/C++ compiler. It's actually pretty simple, just a few dozen lines of code. Check out videos 22/24/25:
https://www.youtube.com/watch?v=WMSBRk5WG58
In game design, the rationale is to be able to more quickly tune constants to find the emotional tenor you are aiming for. Things like game feel, non-player behavior scripts and setpiece lighting/ambience benefit a lot from this.