我想更好地理解其中的区别。我在网上找到了很多解释,但它们都倾向于抽象的差异,而不是实际的含义。
Most of my programming experiences has been with CPython (dynamic, interpreted), and Java (static, compiled). However, I understand that there are other kinds of interpreted and compiled languages. Aside from the fact that executable files can be distributed from programs written in compiled languages, are there any advantages/disadvantages to each type? Oftentimes, I hear people arguing that interpreted languages can be used interactively, but I believe that compiled languages can have interactive implementations as well, correct?
首先,澄清一下,Java不是完全静态编译和以c++的方式链接的。它被编译成字节码,然后由JVM解释。JVM可以对本机机器语言进行即时编译,但不必这样做。
更重要的是:我认为交互性是主要的实际区别。由于所有内容都是解释的,所以您可以截取一小段代码,解析并根据环境的当前状态运行它。因此,如果您已经执行了初始化变量的代码,则可以访问该变量,等等。它真的很适合函数式风格。
然而,解释成本很高,特别是当您有一个包含大量引用和上下文的大型系统时。根据定义,这是一种浪费,因为相同的代码可能必须解释和优化两次(尽管大多数运行时都为此进行了缓存和优化)。不过,您仍然需要支付运行时成本,并且经常需要运行时环境。您也不太可能看到复杂的过程间优化,因为目前它们的性能还没有充分的交互性。
因此,对于不会有太大变化的大型系统,以及某些语言,更有意义的是预编译和预链接所有内容,做所有可以做的优化。最终会得到一个非常精简的运行时,该运行时已经针对目标机器进行了优化。
至于生成可执行文件,恕我直言,这一点关系不大。通常可以从编译语言创建可执行文件。但是您也可以使用解释语言创建可执行文件,只不过解释器和运行时已经打包在可执行文件中,并且对您隐藏了。这意味着您通常仍然需要支付运行时成本(尽管我确信对于某些语言,有方法将所有内容转换为可执行树)。
我不同意所有的语言都可以互动。某些语言,如C语言,与机器和整个链接结构紧密相连,我不确定您是否能够构建一个有意义的完整的交互式版本
极端和简单的情况:
A compiler will produce a binary executable in the target machine's native executable format. This binary file contains all required resources except for system libraries; it's ready to run with no further preparation and processing and it runs like lightning because the code is the native code for the CPU on the target machine.
An interpreter will present the user with a prompt in a loop where he can enter statements or code, and upon hitting RUN or the equivalent the interpreter will examine, scan, parse and interpretatively execute each line until the program runs to a stopping point or an error. Because each line is treated on its own and the interpreter doesn't "learn" anything from having seen the line before, the effort of converting human-readable language to machine instructions is incurred every time for every line, so it's dog slow. On the bright side, the user can inspect and otherwise interact with his program in all kinds of ways: Changing variables, changing code, running in trace or debug modes... whatever.
说完了这些,让我来解释一下,生活不再那么简单了。例如,
Many interpreters will pre-compile the code they're given so the translation step doesn't have to be repeated again and again.
Some compilers compile not to CPU-specific machine instructions but to bytecode, a kind of artificial machine code for a ficticious machine. This makes the compiled program a bit more portable, but requires a bytecode interpreter on every target system.
The bytecode interpreters (I'm looking at Java here) recently tend to re-compile the bytecode they get for the CPU of the target section just before execution (called JIT). To save time, this is often only done for code that runs often (hotspots).
Some systems that look and act like interpreters (Clojure, for instance) compile any code they get, immediately, but allow interactive access to the program's environment. That's basically the convenience of interpreters with the speed of binary compilation.
Some compilers don't really compile, they just pre-digest and compress code. I heard a while back that's how Perl works. So sometimes the compiler is just doing a bit of the work and most of it is still interpretation.
最后,现在,解释和编译是一种权衡,花费(一次)编译的时间通常会获得更好的运行时性能,但解释环境提供了更多的交互机会。编译与解释主要是“理解”程序的工作如何在不同的过程之间划分的问题,而如今,由于语言和产品试图提供两者的最佳服务,这条界线有点模糊。
编译语言是这样一种语言:程序一旦编译,就用目标机器的指令来表达。例如,源代码中的加法“+”操作可以直接转换为机器代码中的“ADD”指令。
解释型语言是指指令不直接由目标机器执行,而是由其他程序(通常用本机语言编写)读取和执行的语言。例如,相同的“+”操作将在运行时被解释器识别,然后调用它自己的“add(a,b)”函数,并使用适当的参数,然后执行机器代码“add”指令。
你可以在编译语言中做你在解释语言中可以做的任何事情,反之亦然——它们都是图灵完备的。然而,这两种方法在实施和使用方面都有优点和缺点。
我将完全概括(纯粹主义者原谅我!),但大致来说,以下是编译语言的优点:
通过直接使用目标计算机的本机代码获得更快的性能
有机会在编译阶段应用相当强大的优化
下面是解释型语言的优点:
更容易实现(编写好的编译器非常困难!!)
不需要运行编译阶段:可以直接“动态”执行代码
是否可以更方便地使用动态语言
注意,字节码编译等现代技术增加了一些额外的复杂性——这里发生的情况是,编译器的目标是一个与底层硬件不同的“虚拟机”。这些虚拟机指令可以在稍后阶段再次编译,以获得本机代码(例如,由Java JVM JIT编译器完成)。
编译器和解释器做同样的工作:将一种编程语言翻译成另一种编程语言,通常更接近硬件,通常是直接可执行的机器代码。
Traditionally, "compiled" means that this translation happens all in one go, is done by a developer, and the resulting executable is distributed to users. Pure example: C++.
Compilation usually takes pretty long and tries to do lots of expensive optmization so that the resulting executable runs faster. End users don't have the tools and knowledge to compile stuff themselves, and the executable often has to run on a variety of hardware, so you can't do many hardware-specific optimizations. During development, the separate compilation step means a longer feedback cycle.
Traditionally, "interpreted" means that the translation happens "on the fly", when the user wants to run the program. Pure example: vanilla PHP. A naive interpreter has to parse and translate every piece of code every time it runs, which makes it very slow. It can't do complex, costly optimizations because they'd take longer than the time saved in execution. But it can fully use the capabilities of the hardware it runs on. The lack of a separrate compilation step reduces feedback time during development.
But nowadays "compiled vs. interpreted" is not a black-or-white issue, there are shades in between. Naive, simple interpreters are pretty much extinct. Many languages use a two-step process where the high-level code is translated to a platform-independant bytecode (which is much faster to interpret). Then you have "just in time compilers" which compile code at most once per program run, sometimes cache results, and even intelligently decide to interpret code that's run rarely, and do powerful optimizations for code that runs a lot. During development, debuggers are capable of switching code inside a running program even for traditionally compiled languages.
开始用“过去的冲击波”来思考
很久很久以前,有一个计算机王国
解释器和编译器。的优点引起了各种各样的争论
一个比另一个。当时的普遍意见是这样的:
解释器:快速开发(编辑和运行)。执行速度慢,因为每个语句都必须被解释为
每次执行的机器代码(想想这对于执行了数千次的循环意味着什么)。
编译器:开发(编辑、编译、链接和运行)缓慢。编译/链接步骤可能会花费大量时间)。快
来执行。整个程序已经是原生机器代码了。
运行时有一到两个数量级的差异
解释程序和编译程序之间存在性能差异。其他的区别
点,例如代码的运行时可变性,也有一些兴趣,但主要是
区别围绕着运行时性能问题。
今天的情况已经发展到这样的程度,编译/解释的区别是
几乎无关紧要。许多
编译语言调用的运行时服务并非如此
完全基于机器代码。而且,大多数解释型语言都被“编译”成字节码
之前执行。字节码解释器非常高效,可以与一些编译器生成的解释器相匹敌
从执行速度的角度来看代码。
典型的区别是编译器生成本机机器码,解释器读取源代码
使用某种运行时系统动态生成机器代码。
如今,经典的诠释者已所剩无几——几乎全部
编译成字节码(或其他一些半编译状态),然后在虚拟“机器”上运行。
从http://www.quora.com/What-is-the-difference-between-compiled-and-interpreted-programming-languages
There is no difference, because “compiled programming language” and
“interpreted programming language” aren’t meaningful concepts. Any
programming language, and I really mean any, can be interpreted or
compiled. Thus, interpretation and compilation are implementation
techniques, not attributes of languages.
Interpretation is a technique whereby another program, the
interpreter, performs operations on behalf of the program being
interpreted in order to run it. If you can imagine reading a program
and doing what it says to do step-by-step, say on a piece of scratch
paper, that’s just what an interpreter does as well. A common reason
to interpret a program is that interpreters are relatively easy to
write. Another reason is that an interpreter can monitor what a
program tries to do as it runs, to enforce a policy, say, for
security.
Compilation is a technique whereby a program written in one language
(the “source language”) is translated into a program in another
language (the “object language”), which hopefully means the same thing
as the original program. While doing the translation, it is common for
the compiler to also try to transform the program in ways that will
make the object program faster (without changing its meaning!). A
common reason to compile a program is that there’s some good way to
run programs in the object language quickly and without the overhead
of interpreting the source language along the way.
You may have guessed, based on the above definitions, that these two
implementation techniques are not mutually exclusive, and may even be
complementary. Traditionally, the object language of a compiler was
machine code or something similar, which refers to any number of
programming languages understood by particular computer CPUs. The
machine code would then run “on the metal” (though one might see, if
one looks closely enough, that the “metal” works a lot like an
interpreter). Today, however, it’s very common to use a compiler to
generate object code that is meant to be interpreted—for example, this
is how Java used to (and sometimes still does) work. There are
compilers that translate other languages to JavaScript, which is then
often run in a web browser, which might interpret the JavaScript, or
compile it a virtual machine or native code. We also have interpreters
for machine code, which can be used to emulate one kind of hardware on
another. Or, one might use a compiler to generate object code that is
then the source code for another compiler, which might even compile
code in memory just in time for it to run, which in turn . . . you get
the idea. There are many ways to combine these concepts.
我猜这是计算机科学中最大的误解之一。
因为解释和编译是完全不同的两件事,我们不能用这种方式进行比较。
编译是将一种语言翻译成另一种语言的过程。编译的类型很少。
编译-将高级语言转换为机器/字节代码(例如:C/ c++ /Java)
翻译——将高级语言翻译成另一种高级语言(例如:TypeScript)
解释是实际执行程序的过程。这可能以几种不同的方式发生。
Machine level interpretation - This interpretation happens to the code which is compiled into machine code. Instructions are directly interpreted by the processor. Programming languages like C/C++ generate machine code, which is executable by the processor. So the processor can directly execute these instructions.
Virtual machine level interpretation - This interpretation happens to the code which is not compiled into the machine level (processor support) code, but into some intermediate-level code. This execution is done by another software, which is executed by the processor. At this time actually processor doesn't see our application. It just executing the virtual machine, which is executing our application. Programming languages like Java, Python, C# generate a byte code, which is executable by the virtual interpreter/machine.
所以在一天结束的时候,我们必须明白的是,世界上所有的编程语言都应该在某个时候进行解释。它可以由处理器(硬件)或虚拟机完成。
编译只是将我们编写的人类可理解的高级代码带到机器可理解的硬件/软件级别的过程。
这是完全不同的两件事,我们无法比较。但是这些术语非常适合教给初学者编程语言是如何工作的。
PS:
Some programming languages like Java have a hybrid approach to do this. First, compile the high-level code into byte code which is virtual-machine readable. And on the fly, a component called the JIT compiler compiles byte-code into machine code. Specifically, code lines that are executed again and again many times are get translated into the machine language, which makes the interpretation process much faster. Because hardware processor is always much faster than virtual interpreter/processor.
Java JIT编译器如何工作