当前位置: 首页 > 工具软件 > SpiderMonkey > 使用案例 >

脚本引擎小PK: SpiderMonkey vs V8

江承嗣
2023-12-01

介绍

    SpiderMonkey是Firefox使用的脚本引擎,V8是Google Chrome使用的脚本引擎。这篇文章介绍了怎样在自己的C++程序中嵌入这两种脚本引擎,以及简单做了一些横向的对比。

 

编译

SpiderMonkey                                                                                                           

 

SpiderMonkey支持1.0~1.8版本的JavaScript语法,包括ECMAScript,ECMA 263-3,以及Mozilla扩展,可选支持E4X

由于SpiderMonkey的makefile只支持GNU Make。为了便于编译,建议使用MSYS,请先准备好MSYS(http://www.mingw.org

下载SpiderMonkey源代码(https://developer.mozilla.org/En/SpiderMonkey/1.8)

解压...

  1. 从“VC命令提示”进入控制台,然后进入到MSYS中,这样做的目的是为了让MSYS能使用VC的编译器。
  2. 在MSYS里,用cd命令进入到SpiderMonkey源代码目录中
  3. 输入make -f makefile.ref BUILD_OPT=1

这样就编译完成了,还算简单吧。

BUILD_OPT=1参数的作用是把SpiderMonkey编译成Release版本。

另外,默认是使用VC的运行库的(即使用-MD编译参数),如果不喜欢,可以修改src/confg目录下的*.mk文件(比如把-MD改成-MT)

对于MinGW用户,请参考这里http://jargon.ca/spidermonkey/编译

 

V8                                                                                                                        

 

不知道Google为什么把他们的脚本引擎称为V8,其宣称V8的速度远远超过SpiderMonkey,同样支持支持ECMAScript、ECMA-262-3。

下载V8源代码,需要安装SVN,命令是svn checkout http://v8.googlecode.com/svn/trunk/ v8

下载后解压...

可以在tools/visual_studio里找到工程文件,直接打开工程文件就可以编译了。

如果编译成功,可以无视下面这段。如果没搞定,请静下心来继续...

命令行编译方法

需要Python2.4以上版本(http://www.python.org )

安装scons(http://www.scons.org ),这是一个python的编译脚本软件,可以把它看作是“高级”一点的make。

  1. 进入“VC命令提示”
  2. 进入V8目录
  3. 设置Python路径 set path=c:/Python25;c:/Python25/Scripts;%path%

官方文档说到这一步输入scons就可以开始编译了

不过例外总是有的,比如我的VC2005就不行,一会儿说找不到cl命令,一会儿又找不到头文件-_-

我们得告诉它环境变量的值,这样写就可以了:

scons env="PATH:%path%,INCLUDE:%include%,LIB:%lib%"

默认是静态链接,静态VC库,可以这样修改编译参数

scons library=shared msvcrt=shared env=...

输入scons --help能看到更多编译参数

想在MinGW里编译,要到这里下个补丁才行:http://codereview.chromium.org/18309

注意:如果编译成动态库,使用时包含头文件v8.h之前应该先来一句 #define USING_V8_SHARED 1

对比

    只是简单地比较一下脚本运行速度、脚本与宿主程序之间通信速度以及编程的简易程度。我想这也是C++编程人员关心的主要问题。

 

比较用的脚本:                                                                                                      

 

这是一个从网上找来的计算Pi的JS脚本:

  1. mess="";
  2. //10^11 seems to be the maximum
  3. //too high a figure for the base introduces errors
  4. Base=Math.pow(10,11);
  5. //num digits in each array item
  6. cellSize=Math.floor(Math.log(Base)/Math.LN10);
  7. //below is not used in this script
  8. a=Number.MAX_VALUE;
  9. MaxDiv=Math.floor(Math.sqrt(a));
  10. function makeArray (n, aX, Integer) {
  11.     var i=0;
  12.     for (i=1; i<n; i++)
  13.         aX[i] = null;
  14.     aX[0] = Integer;
  15. }
  16. function isEmpty (aX) {
  17.     var empty=true
  18.         for (i=0; i<aX.length; i++)
  19.             if (aX[i])
  20.             {
  21.                 empty= false;
  22.                 break;
  23.             }
  24.     return empty;
  25. }
  26. //junior school math
  27. function Add (n, aX,aY) {
  28.     carry=0
  29.         for (i=n-1; i>=0; i--) {
  30.             aX[i] += Number(aY[i])+Number(carry);
  31.             if (aX[i]<Base)
  32.                 carry = 0;
  33.             else {
  34.                 carry = 1;
  35.                 aX[i] =Number(aX[i])- Number(Base);
  36.             }
  37.         }
  38. }
  39. //subtract
  40. function Sub (n, aX,aY) {
  41.     for (i=n-1; i>=0; i--) {
  42.         aX[i] -= aY[i];
  43.         if (aX[i]<0) {
  44.             if (i>0) {
  45.                 aX[i] += Base;
  46.                 aX[i-1]--;
  47.             }
  48.         }
  49.     }
  50. }
  51. //multiply big number by "small" number
  52. function Mul (n, aX, iMult) {
  53.     carry=0;
  54.     for (i=n-1; i>=0; i--) {
  55.         prod = (aX[i])*iMult;
  56.         prod += carry;
  57.         if (prod>=Base) {
  58.             carry = Math.floor(prod/Base);
  59.             prod -= (carry*Base);
  60.         }
  61.         else
  62.             carry = 0;
  63.         aX[i] = prod;
  64.     }
  65. }
  66. //divide big number by "small" number
  67. function Div (n, aX, iDiv,aY) {
  68.     carry=0;
  69.     for (i=0; i<n; i++) {
  70.         //add any previous carry
  71.         currVal = Number(aX[i])+Number(carry*Base);
  72.         //divide
  73.         theDiv =Math.floor(currVal/iDiv);
  74.         //find next carry
  75.         carry = currVal-theDiv*iDiv;
  76.         //put the result of division in the current slot
  77.         aY[i] = theDiv;
  78.     }
  79. }
  80. //compute arctan
  81. function arctan (iAng, n, aX) {
  82.     iAng_squared=iAng*iAng;
  83.     k=3; //k is the coefficient in the series 2n-1, 3,5..
  84.     sign=0;
  85.     makeArray (n, aX, 0); //aX is aArctan
  86.     makeArray (n, aAngle, 1);
  87.     Div (n, aAngle, iAng, aAngle); //aAngle = 1/iAng, eg 1/5
  88.     Add (n, aX, aAngle); // aX = aAngle or long angle
  89.     while (!isEmpty(aAngle)) {
  90.         Div (n, aAngle, iAng_squared, aAngle); //aAngle=aAngle/iAng_squared, iAng_squared is iAng*iAng
  91.         Div (n, aAngle, k, aDivK); /* aDivK = aAngle/k */
  92.         if (sign)
  93.             Add (n, aX, aDivK); /* aX = aX+aDivK */
  94.         else Sub (n, aX, aDivK); /* aX = aX-aDivK */
  95.         k+=2;
  96.         sign = 1-sign;
  97.     }
  98.     mess+="aArctan="+aArctan+"<br>";
  99. }
  100. // Calculate pi
  101. function calcPI (numDec) {
  102.     var ans="";
  103.     t1=new Date();
  104.     numDec=Number(numDec)+5;
  105.     iAng=new Array(10);
  106.     coeff=new Array(10);
  107.     arrayLength=Math.ceil(1+numDec/cellSize);
  108.     aPI = new Array(arrayLength);
  109.     aArctan = new Array(arrayLength);
  110.     aAngle=new Array(arrayLength);
  111.     aDivK=new Array(arrayLength);
  112.     //Pi/4 = 4*arctan(1/5)-arctan(1/239)
  113.     //coeff is an array of the coefficients
  114.     //the last item is 0!
  115.     coeff[0] = 4;
  116.     coeff[1] = -1;
  117.     coeff[2] = 0;
  118.     //iAng holds the angles, 5 for 1/5, etc
  119.     iAng[0] = 5;
  120.     iAng[1] = 239;
  121.     iAng[2] = 0;
  122.     makeArray (arrayLength, aPI, 0);
  123.     //Machin: Pi/4 = 4*arctan(1/5)-arctan(1/239)
  124.     makeArray(arrayLength,aAngle,0);
  125.     makeArray(arrayLength,aDivK,0);
  126.     for (var i=0; coeff[i]!=0; i++) {
  127.         arctan(iAng[i], arrayLength, aArctan);
  128.         //multiply by coefficients of arctan
  129.         Mul (arrayLength, aArctan, Math.abs(coeff[i]));
  130.         if (coeff[i]>0)
  131.             Add (arrayLength, aPI, aArctan);
  132.         else
  133.             Sub (arrayLength, aPI, aArctan);
  134.     }
  135.     //we have calculated pi/4, so need to finally multiply
  136.     Mul (arrayLength, aPI, 4);
  137.     //we have now calculated PI, and need to format the answer
  138.     //to print it out
  139.     sPI="";
  140.     tempPI="";
  141.     //put the figures in the array into the string tempPI
  142.     for (i=0;i<aPI.length;i++)
  143.     {
  144.         aPI[i]=String(aPI[i]);
  145.         //ensure there are enough digits in each cell
  146.         //if not, pad with leading zeros
  147.         if (aPI[i].length<cellSize&&i!=0)
  148.         {
  149.             while (aPI[i].length<cellSize)
  150.                 aPI[i]="0"+aPI[i];
  151.         }
  152.         tempPI+=aPI[i];
  153.     }
  154.     //now put the characters into the string sPI
  155.     for (i=0;i<=numDec;i++)
  156.     {
  157.         //put the 3 on a different line, and add a decimal point
  158.         if (i==0)
  159.             sPI+=tempPI.charAt(i)+". ";
  160.         else
  161.         {
  162.             if ((i)%50==0&&i!=0)
  163.                 sPI+=tempPI.charAt(i)+" ";
  164.             else
  165.                 sPI+=tempPI.charAt(i);
  166.         }//i not zero
  167.     }
  168.     //now put the print-out together
  169.     //print our pi
  170.     ans+=("PI ("+numDec+")="+sPI+" ");
  171.     //Window's calculator Pi (for confirmation);
  172.     ans+=("Win PI= 3.1415926535897932384626433832795 ");
  173.     t2=new Date();
  174.     timeTaken=(t2.getTime()-t1.getTime())/1000;
  175.     ans+="It took: "+timeTaken+" seconds";
  176.     return ans;
  177.  
  178. }
  179.  
  180. myprint(calcPI(1000));

脚本与宿主程序之间通信速度测试脚本

  1. // MyClass是宿主提供给JS的类(一个queue的直接包装)
  2. var c = new MyClass();
  3. t1=new Date();
  4.  
  5. //10万次push和pop,测试JS调用宿主代码的速度
  6. for(i=0; i<100000; i++)
  7. {
  8.     c.push(i);
  9.     c.pop();
  10. }
  11. t2=new Date();
  12. timeTaken=(t2.getTime()-t1.getTime())/1000;
  13. //myprint也是宿主提供的全局函数,用于显示结果
  14. myprint("It took:",timeTaken,"seconds");

(未完待续)

 类似资料: