编译语言 vs 解释语言

阅读:  评论:  作者:Rybby  日期:  来源:rybby.com

一直以为,编译语言的性能绝对比解释语言快,因为就理论而言,解释语言要一边解释(将脚本语言翻译成计算机能识别的语言)一边执行,就工作量来说就比编译语言多一倍。以下是自己心目中长久以来的各种编程语言的性能排行榜:

1)01语言(计算机语言)

2)汇编语言(半计算机语言,低级语言)

3)编译语言(高级语言,如C,C++,C#,JAVA等等)

4)解释语言(脚本语言,如Javascript,VBscript,Node等等)

直到最近,在锐某开发TTD(Thick Text Database/胖文本数据库)的过程中,因为自己是用 Node.js 进行开发的,后来觉得也许用编译语言能获得更高的性能,于是花了几天时间来翻阅C语言的资料,我的电脑磁盘里都保存有各种编程语言的电子书(PDF,CHM,TXT等等),由于自己只用脚本语言开发些网络程序,对软件程序开发没兴趣,所以一直没学这些语言,如果我要设计软件程序,唯一考虑的是汇编语言,很多高级语言都是程序猿为了偷懒而将许多东西封装起来,性能当然大打折扣!本来就打算用汇编来写TTD的,但因为汇编太难学了,只好先学C了。看了几天C的资料,简单入门之后写了个测试程序,结果太坑人啦!编译语言 C 完全输给了解释语言 Node!以下是锐某的测试程序源码:

C语言

程序名:test1.c
#include
#include
void main()
{
unsigned long a = 0, b, *c, d = 1000000000;
time_t t1, t2;
c = &a;
t1 = time(NULL);
for(; a < 1000000000;) a++;
t2 = time(NULL);
b = (t2-t1)*1000;/*以毫秒计算耗时*/
printf("t1 = %lu s\nt2 = %lu s\ntimeDiffer = %lu ms", t1, t2, b);
}

程序名:test2.c
#include
#include
void main()
{
unsigned long a = 0, b, *c, d = 1000000000;
time_t t1, t2;
c = &a;
t1 = time(NULL);
for(; a < d;) a++;
t2 = time(NULL);
b = (t2-t1)*1000;/*以毫秒计算耗时*/
printf("t1 = %lu s\nt2 = %lu s\ntimeDiffer = %lu ms", t1, t2, b);
}

程序名:test3.c
#include
#include
void main()
{
unsigned long a = 0, b, *c, d = 1000000000;
time_t t1, t2;
c = &a;
t1 = time(NULL);
for(; *c < 1000000000;) ++*c;
t2 = time(NULL);
b = (t2-t1)*1000;/*以毫秒计算耗时*/
printf("t1 = %lu s\nt2 = %lu s\ntimeDiffer = %lu ms", t1, t2, b);
}

Node.js

程序名:test1.js
(function test() {
var a = 0, b = 1000000000;
console.time('time');
for(; a < 1000000000;) a++;
console.timeEnd('time');
})()

程序名:test2.js
(function test() {
var a = 0, b = 1000000000;
console.time('time');
for(; a < b;) a++;
console.timeEnd('time');
})()

程序名:test3.js
(function test() {
var a = 0, b = 1000000000, c = Array(1000000000);
console.time('time');
for(; a < c.length;) a++;
console.timeEnd('time');
})()

下面我们来比较结果,所有的例子都反复执行几次,通过目测取平均值,如果要更精确的统计结果至少要执行100次以上,然后取平均值,有兴趣的网友可以自行测试。C程序我是用TC2编译的,至于js程序,大家可以将源码保存为相应的程序名,然后放到Node目录,在Node终端输入如下命令即可:node test1.js

本程序用于计算10亿次加法运算所耗的时间,test1.c 总耗时:35000 ms,每次加法运算耗时 35000*1000*1000/1000000000=35 纳秒(1秒=1*1000毫秒*1000微秒*1000纳秒*1000皮秒*1000飞秒*1000渺秒);test1.js 总耗时:6500 ms,每次加法运算耗时 6.5 纳秒。test2.c 总耗时:60000 ms,每次加法运算耗时 60 纳秒;test2.js 总耗时:5300 ms,每次加法运算耗时 5.3 纳秒,同样的操作,C语言所耗的时间是Node的10多倍!!!这里还仅仅测试了加法的运算而已,如果for循环里还有其它一些表达式语句...
PS:测试PC为神州笔记本优雅Q,CPU:N270,1.60GHZ,内存:1G,很老的机器了。

在测试的过程中发现个有趣的现象,test2.c 所耗的时间是 test1.c 60000/35000=1.7倍,主要原因是 test2.c 用变量“d”来代替实数“1000000000”,使用变量内容的过程是先找到变量的地址才能找到内容,时间就花在这上面了。而Node则刚好相反,test2.js 所耗的时间是 test1.js 5300/6500=0.8倍,Node使用变量反而比实数快!锐某不明白她的变量内容是如何取的,于是又写了 test3.js测试了使用对象属性的耗时,通过实例我们可以看到for循环的耗时按快到慢的排序是:for(;z<变量;) < for(;z<对象的属性(str.length|arr.lenth);) < for(;z<整数;),结果很令人郁闷!因为锐某想象中的排序应该是:for(;z<整数;) < for(;z<变量;) < for(;z<对象的属性(str.length|arr.lenth);),似乎 javascript 中for循环的耗时排序就是按后者排的,这个我没测试过,不过测试了其它一些表达式,如:字符串连接,在 javascript 与 php 中,用 arr.push(str) 比 str += str 要快得多,在不同的浏览器中二者的差别更是明显,比如在 IE 这个臭家伙中,两者的差别简直是一个在天一个在地!但是这些表达式在Node里几乎没有太大的差别。

另外锐某还发现个很惊人的东西,那就是大多数人都以为程序语言自带的函数肯定比程序猿自定义的函数快,因为程序语言自带的函数都经过编译好了,而程序猿自定义的在运行过程中一边解释一边执行,事实是否真如此呢,让我们来一探究竟。我们要将一段字符串转对象,大家常用的都是建立一串json格式的字串,然后用程序自带的函数实现对象化,比如Node里就有这么一个 JSON.parse(),但是锐某自己写的方法却能比这个快至少6倍,原理很简单,我们不需要用json这样垃圾的东西,至少我觉得她很垃圾,不但占空间、耗时间!还很麻烦!因为她用了很多符号,而我们要用这些符号必须经过转义。我们可以用另一种格式:
name^value^name^value^name^value^name^value...
str to obj
var arr, obj, l, z;
arr = str.split('^');
obj = {};
l = arr.length;
for(z = 0; z < l; z+=2) obj[arr[z]] = arr[z+1];

锐某觉得 JSON.parse 之所以慢,应该是她要对每个属性的值都要判断是否还有子对象或属性,时间就是这样被浪费掉了!很多封装的东西都要考虑针对各种各样的情况进行处理,如果我们对自己的数据格式或结构很清晰,根本不需要考虑其它的情况,这样就省下了很多的时间。很多网友一开始学一种语言就库呀、类呀、模块呀什么的,别人写的东西都不一定适合自己用,还是按自己喜欢的方法从底层开始写,那样可以对自己的程序为所欲为的操作。如果对别人的程序不是很了解,在使用过程中出现问题就不知道从哪里开始处理。锐某还是那句话,多走弯路多犯错!这会为你积累非常宝贵的经验!

最后说一下关于C语言的东西,锐某对C不是很了解,呀!应该说完全不了解!鉴于上面的性能测试例子,test2.c 使用 for(; a < d;) 竟然比 test1.c 使用 for(; a < 1000000000;) 慢了1.7倍,仅仅使用了一个变量,就有如此大的差距,如果程序中还用了很多变量呢?出于好奇,我又写了 test3.c 进行测试,这个例子用了指针,但性能跟变量也没有多大差别,或许指针不是这样用的吧?如果不是这样用那应该怎样用?一直很不解,C语言为什么要引入指针这种概念?有种脱裤子放屁的嫌疑,用变量就能取到内容为什么还要绕个圈圈通过指针来取进而增加内存空间。当然如果增加内存空间能带来性能的提升还是可以理解的,因为这个时代是以空间换时间的时代。指针究竟能带来多大的性能?我不知道,我唯一知道的是指针存放变量的地址,通过地址能够快速找到变量的内容,如果用变量就多了找地址这一步。指针到底有哪些优点,希望有大牛写些实例来测试一下,锐某感激不尽!

编译语言 vs 解释语言的更多相关文章

  1. JAVA与编译语言及解释语言的关系

    转自JAVA结合了编译和解释执行的优点 编译型语言是一次性编译成机器码,脱离开发环境独立运行,所以运行效率较高,但是由于编译成的是特定平台上机器码,所以可移植性差. 编译型语言的典型代表有C.C++. ...

  2. 设计模式-Interpreter(行为模式) 使用解释器给用户提供一个一门定义语言的语法表示的解释器,通过该解释器解释语言中的句子。

    //以下代码来源: 设计模式精解-GoF 23种设计模式解析附C++实现源码 //Context.h #pragma once class Context { public: Context(); ~ ...

  3. Java跨平台原理

    此篇博文主要源自网络xiaozhen的天空的博客:http://xiaozhen1900.blog.163.com/blog/static/1741732572011325111945246/ 1.是 ...

  4. 【转】Java跨平台原理

    原文地址:http://www.cnblogs.com/gw811/archive/2012/09/09/2677386.html 1.是么是平台 Java是可以跨平台的编程语言,那我们首先得知道什么 ...

  5. 《疯狂java讲义》笔记 1-5章

    1.编译语言和解释语言理解,摘自李刚老师的<疯狂Java讲义>第三版: 就是说,Java和.net都是编译型有事解释型语言.编译型就是根据不同平台编译成不同的可执行机器码,编译过程中会进行 ...

  6. 笔试总结篇(一) : 广州X公司笔试

    一.单选题: Ps : 当时由于去广州路上颠簸很困,导致刚做几分钟题目就睡了一觉.起来发现20分钟过去了.擦擦! 1. 假设磁盘文件foobar.txt 由 6个ASCII 码字符“foobar” 组 ...

  7. 编译和解释性语言和python运行方式

    1.编译型语言和解释性语言 编译型语言:在执行之前需要一个专门的编译过程,把程序编译成为机器语言的文件,运行时不需要重新翻译,直接使用编译的结果就行了.程序执行效率高,依赖编译器,跨平台性差些.如C. ...

  8. React++ node.js ++SQL Sever ++MySQL++ python ++ php ++ java ++ c++ c#++ java ++ android ++ ios ++Linux+

    "C语言在它诞生的那个年代,是非常不错的语言,可惜没有OOP.当项目臃肿到一定程度,人类就不可控了. 为了弥补这个缺陷,C++诞生了.而为了应对各种情况,C++设计的大而全,太多复杂的特性, ...

  9. java笔记--问题总结

    1. 垃圾回收算法 标记-清除算法 标记-清除算法是最基本的算法,和他的名字一样,分为两个步骤,一个步骤是标记需要回收的对象.在标记完成后统一回收被标记的对象.这个算法两个问题.一个是效率问题,标记和 ...

随机推荐

  1. EqualsBuilder 类的使用

    apache的commons-lang包提供了一个EqualsBuilder类,提供了基本属性.数组.对象等比较操作的封装,可以辅助实现对象的equals(Object)方法. 这个类的使用比较简单, ...

  2. [Python] String strip() Method

    Description The method strip() returns a copy of the string in which all chars have been stripped fr ...

  3. springboot 测试 有注入HttpSession的bean

    question: nested exception is java.lang.IllegalStateException: No thread-bound request found: Are yo ...

  4. django-auth组件的权限管理

    一:自定义权限验证 1.在model中的Meta类自定义权限码 class WorkUser(models.Model): username = models.CharField(u'用户名', ma ...

  5. 好记性不如烂笔头-linux学习笔记3mysql数据库导入导出

    1 数据库文件导出 mysqldump -uroot -p123456 test > 1.sql 2数据库文件导入 mysql -uroot -p123456 test <1.sql 3 ...

  6. mybatis 1 - 获取自增ID

    1.环境: mybatis : 3.2.3 spring-mybatis:  1.2.1 mysql:5.5.29 实体: public class sys_user { private int us ...

  7. JDK常用命令

    转自:https://www.cnblogs.com/saiQsai/p/10353044.html 1.jps 查看java进程,得到进程ID:7854 作用等同于:ps -ef | grep ja ...

  8. MySQL GTID (四)

    七. GTID的限制以及解决方案 7.1 事务中混合多个存储引擎,会产生多个GTID. 当使用GTID,在同一个事务中,更新包括了非事务引擎(MyISAM)和事务引擎(InnoDB)表的操作,就会导致 ...

  9. XE: Changing the default http port

    Oracle XE uses the embedded http listener that comes with the XML DB (XDB) to serve http requests. T ...

  10. PIN 引脚类型

    一个 capture filter 通常有两个或更多个输出相同类型数据的输出引脚,例如预览引脚和捕捉引脚.因此,媒体类型不是区分引脚的好方法. //相反,这些引脚通过它们的功能来区分,这些功能是使用称 ...