编译还是解释?

我们可能要问,什么时候应该用编译,什么时候应该用解释呢?最终的结果是几乎相同,因此,答案通常最终归结为生成代码的原始速度,虽然内存使用情况和启动时间也是主要的关注。如果需要代码执行得更快,那么编译通常是更好的结果,有一定的优势。

清单 12-8 的测试工具,能够重复执行 interpret 函数中的 createDynamicMethod 方法,计算出花费的时间;还测试在动态方法上的重要变化。这还生成一个新的 .NET 委托值,作为该句柄,调用生成的代码。可以看出,这是到目前为止最快的技术。记住,评估抽象语法树花费的时间,可以是直接地,也可以是以编译形式,没有测量出解析时间或编译时间。

清单 12-8 比较性能的测试工具

open System

open System.Diagnostics

openStrangelights.Expression

//expression to process

let e = Multi(Val 2.,Plus(Val 2., Val 2.))

//collect the inputs

printf"Interpret/Compile/CompileThrough Delegate [i/c/cd]: "

let interpertFlag =
Console.ReadLine()

printf"reps: "

let reps = int(Console.ReadLine())

type
Df0 = delegate ofunit
-> float

type
Df1 = delegate offloat
-> float

type
Df2 = delegate offloat *
float -> float

type
Df3 = delegate offloat *
float *
float -> float

type
Df4 = delegate offloat *
float *
float * float
-> float

//run the tests

match interpertFlag
with

| "i"
->

let args = Interpret.getVariableValues e

let clock =
new Stopwatch()

clock.Start()

for i = 1
to reps do

Interpret.interpret e args |> ignore

clock.Stop()

printf "%i" clock.ElapsedTicks

| "c"
->

let paramNames = Compile.getParamList e

let dm = Compile.createDynamicMethod e paramNames

let args = Compile.collectArgs paramNames

let clock =
new Stopwatch()

clock.Start()

for i = 1
to reps do

dm.Invoke(null, args) |> ignore

clock.Stop()

printf "%i" clock.ElapsedTicks

| "cd"
->

let paramNames = Compile.getParamList e

let dm = Compile.createDynamicMethod e paramNames

let args = Compile.collectArgs paramNames

let args = args |>
Array.map (fun f
-> f :?> float)

let d =

match args.Length
with

| 0 ->dm.CreateDelegate(typeof<Df0>)

| 1 ->dm.CreateDelegate(typeof<Df1>)

| 2 ->dm.CreateDelegate(typeof<Df2>)

| 3 ->dm.CreateDelegate(typeof<Df3>)

| 4 ->dm.CreateDelegate(typeof<Df4>)

| _ -> failwith
"too manyparameters"

let clock =
new Stopwatch()

clock.Start()

for i = 1
to reps do

match d
with

| :? Df0
as d -> d.Invoke() |>ignore

| :? Df1 as d
-> d.Invoke(args.[0])|> ignore

| :? Df2 as d
-> d.Invoke(args.[0],args.[1]) |> ignore

| :? Df3 as d
-> d.Invoke(args.[0],args.[1], args.[2]) |> ignore

| :? Df4 as d
-> d.Invoke(args.[0],args.[1], args.[2], args.[4]) |> ignore

| _ -> failwith
"too manyparameters"

clock.Stop()

printf "%i" clock.ElapsedTicks

| _ -> failwith
"not anoption"

12-2汇总了执行程序计算表达式 Multi(Val2.,Plus(Val 2., Val 2.)) 的结果。

表 12-2汇总处理表达式 Multi(Val 2.,Plus(Val 2., Val 2.)),重复不同的次数(每微秒次数)


重复次数


1


10


100


1,000


10,000


100,000


1,000,000


解释


6,890


6,979


6,932


7,608


14,835


84,823


799,788


通过委托编译


8,65


856


854


1,007


2,369


15,871


151,602


编译


1,112


1,409


2,463


16,895


151,135


1,500,437


14,869,692

从表12-2 和图12-2 中可以看出,编译和通过委托编译在重复次数少时更快。但是,注意,重复1、10 和 100 次,需要的时间增长不明显,这是因为重复数量小,每次重复花费的时间不明显;真正花费的时间是即时编译器(JIT)用来把中间语言代码编译成本地代码,这是相对显著的。这就是为什么编译和通过委托编译的时间很接近,它们即时编译的代码数量相似;而解释花费更长的时间,是因为必须即时编译更多的代码,特别是解释器。但是,即时编译是一次性成本,每个方法只需要即时编译一次,因此,随着重复次数的增加,一次性的成本已经支付,这才真正看到相对性能成本的图像。

图 12-2 评估表达式1 + 1 的时间花费随计算次数的变化

[

图与程序已经不配套了,图还是原来的版本,程序是新的

]

从图12-2 可以看得更清楚,随着重复数量的增加,编译的成本急剧上升。这是因为,访问编译过的 DynamicMethod 方法通过调用Invoke,这是很昂贵的,每重复一次就增加一次成本,因此,用于编译的方法的耗时与重复的次数成正比。然而,问题在于不使用编译,而在于如何调用编译的代码。事实证明,通过委托调用 DynamicMethod,而不是在动态委托上的Invoke 成员,能够一次性的绑定方法的成本,因此,在打算多次评估表达式时,执行DynamicMethod,这种方法更有效。从这些结果来看,通过委托编译请求在速度方面最好的。

这个分析还表明测量的重要性,不要认为编译一定能筛期望的性能收益,除非真的看到针对具体数据集的好处,使用所有可用的技术来确保代码中没有不必要的躲藏开销。然而,现实中还会有其他许多因素,例如,如果表达式经常改变,解释器会要求再次即时编译一次。每次编译表达式将需要即时编译,因此,如果想看到任何性能提升,需要多次运行编译的代码。鉴于解释代码通常更容易实现,编译码仅在某些特定情况下才提供了显著的性能提升,因此,解释通常是一种更好的选择。

当处理的情况是需要尽可能快地执行代码,通常最好的方法是尝试不同的几个方法,然后,分析应用程序,看哪一种方法获得更好的结果。有关性能分析的更多内容,请看第十二章。

[

最后这一句话可能已经远处着落了。

本章就是第十二章。

原来的第十二章是“工具套件、NET 编程工具”,在新版本中好像没有了。

]

第十二章小结

在这一章,我们学习了 F# 中面向语言编程的主要特点与技术。可以看到有不同的技术,有使用数据结构作为小语言,或者使用引用,都涉及到对现有 F# 语法的改变或扩展;其他的,比如实现解析器,可以处理任何基于文本的语言,不管这种语言是自己设计的,或者,更常见的是已有的语言。所有这些技术,如能正确使用,都能极大地提高生产力。

下一章,我们将看一下如何使用 F# 解析文本,可以用它来创建不需要嵌入在 F# 的语言,也可以处理定义好的主要文本格式。

编译还是解释?

时间: 2024-10-03 15:01:25

编译还是解释?的相关文章

编译型和解释型的区别&amp;&amp;Java从编译到执行的过程

借鉴: 1  http://www.cnblogs.com/bluestorm/archive/2012/12/09/2810167.html           区别 2  http://blog.jobbole.com/53152/       编译的过程 3  http://jingyan.baidu.com/article/b24f6c82de6bcf86bfe5dad4.html          Java从编译到执行的过程(完整) Java编译-下载-解释-执行的过程: 在Java编

编译和解释的区别是什么?

编译器是把源程序的每一条语句都编译成机器语言,并保存成二进制文件,这样运行时计算机可以直接以机器语言来运行此程序,速度很快; 而解释器则是只在执行程序时,才一条一条的解释成机器语言给计算机来执行,所以运行速度是不如编译后的程序运行的快的. 这是因为计算机不能直接认识并执行我们写的语句,它只能认识机器语言(是二进制的形式) 一.低级语言与高级语言最初的计算机程序都是用0和1的序列表示的,程序员直接使用的是机器指令,无需翻译,从纸带打孔输入即可执行得到结果.后来为了方便记忆,就将用0.1序列表示的机

也谈编译 VS 解释

语言发展 计算机的硬件仅仅能识别0和1组成的机器指令,而机器指令是最主要的计算机语言,可是我们平时进行程序设计时肯定不会用机器语言来编程,由于用它的效率低.更让人难以理解. 因此聪明的人类发明了汇编语言.它使用符号来表示指令,比如用ADD表示加法.这就easy理解了.可是汇编语言和机器语言十分接近,其书写取决于机器指令,因此它还是一种面向机器的语言.所以称它为低级语言. 对应的,又在此基础上,开发出了功能更强.抽象更高的面向各类应用的程序语言.称为高级语言.比如VB,C++,C#,Java等,大

编译和解释原理

语言发展 计算机的硬件只能识别0和1组成的机器指令,而机器指令是最基本的计算机语言,但是我们平时进行程序设计时肯定不会用机器语言来编程,因为用它的效率低,更让人难以理解.因此聪明的人类发明了汇编语言,它使用符号来表示指令,例如用ADD表示加法,这就容易理解了.但是汇编语言和机器语言十分接近,其书写取决于机器指令,因此它还是一种面向机器的语言,所以称它为低级语言.相应的,又在此基础上,开发出了功能更强.抽象更高的面向各类应用的程序语言,称为高级语言.例如VB,C++,C#,Java等,大家都挺熟悉

程序的编译与解释之间的区别

个人觉得:取决于你怎么解读这个问题. 传统意义对比: 传统意义上的所谓编译与解释,区别在于代码是在什么时候被翻译成目标CPU的指令.——虽然这种解释从科学上说不通,但这却是一直以来大家更认可的更约定俗成的定义. 对 C 语言或者其他编译型语言来说,编译生成了目标文件,而这个目标文件是针对特定的 CPU 体系的,为 ARM 生成的目标文件,不能被用于 MIPS 的 CPU.这段代码在编译过程中就已经被翻译成了目标 CPU 指令,所以,如果这个程序需要在另外一种 CPU 上面运行,这个代码就必须重新

Python入门——编译和解释

编译和解释 源代码: 采用某种编程语言编写的计算机程序,人类可读 例如:result = 2 + 3 目标代码: 计算机可直接执行的,人类不可读(一般) 例如:11010010 00111011 (机器语言) 将人类编写的程序转变为机器可以直接执行的目标代码,程序执行的两种方式: 编译: 将源代码一次性转换成目标代码的过程,类似英文翻译 解释: 将源代码逐条转换成目标代码同时逐条运行的过程,类似同声传译 根据程序的执行方式不同,编程语言分为两类:静态语言:使用编译执行的编程语言 C/C++语言,

编译与解释的区别

博主今年大三,学校开展了<编译原理>这门课,而老师提的第一个问题便是编译与解释的区别,下面我将会说说自己的看法. 首先我们要知道市面上大致上是有两种类型的语言的:静态语言与动态语言. 静态语言:C/C++,JAVA,C#等等:动态语言:Javascript,Python等等 而静态语言之所以是静态的正是应为它的源文件是需要使用编译器将源程序文件翻译成二进制文件. 我们拿JAVA举例,java是一门典型的强类型静态语言.首先,我们在One.java文件中编写一段程序如下 package com.

Android APK反编译具体解释(附图)

这段时间在学Android应用开发,在想既然是用Java开发的应该非常好反编译从而得到源码吧,google了一下,确实非常easy,下面是我的实践过程. 在此郑重声明,贴出来的目的不是为了去破解人家的软件,全然是一种学习的态度,只是好像通过这样的方式也能够去汉化一些外国软件. 本文Android反编译教程,測试环境: Win7 Ultimate x64 Ubuntu 12.04 x86_x64 反编译工具包 下载 (2012-10-10更新) 一.Apk反编译得到Java源码 下载上述反编译工具

编译与解释(java)

计算机不能直接理解高级语言,只能直接理解机器语言,所以必须要把高级语言翻译成机器语言,计算机才能执行高级语言编写的程序. 翻译的方式有两种,一个是编译,一个是解释.两种方式只是翻译的时间不同 计算机不能直接理解高级语言,只能直接理解机器语言,所以必须要把高级语言翻译成机器语言,计算机才能执行高级语言编写的程序. 翻译的方式有两种,一个是编译,一个是解释.两种方式只是翻译的时间不同. 编译(compilation , compile)定义分为静态和动态两种: 1.利用编译程序从源语言编写的源程序产