Performance Node.js/coffeescript在数学密集型算法上的性能
我正在试验node.js来构建一些服务器端逻辑,并实现了coffeescript和Java中描述的diamond square算法的一个版本。鉴于我对node.js和V8性能的赞扬,我希望node.js不会落后于java版本太多 然而,在4096x4096地图上,Java在1s内完成,但node.js/coffeescript在我的机器上占据了20s的时间 这些是我的全部结果。x轴是网格大小。对数和线性图表: 这是因为我的coffeescript实现有问题,还是这只是node.js的本质 咖啡脚本Performance Node.js/coffeescript在数学密集型算法上的性能,performance,node.js,coffeescript,Performance,Node.js,Coffeescript,我正在试验node.js来构建一些服务器端逻辑,并实现了coffeescript和Java中描述的diamond square算法的一个版本。鉴于我对node.js和V8性能的赞扬,我希望node.js不会落后于java版本太多 然而,在4096x4096地图上,Java在1s内完成,但node.js/coffeescript在我的机器上占据了20s的时间 这些是我的全部结果。x轴是网格大小。对数和线性图表: 这是因为我的coffeescript实现有问题,还是这只是node.js的本质 咖
genHeightField=(sz)->
timeStart=新日期()
数据大小=sz
种子=1000.0
数据=新数组()
iters=0
#预热阵列,告诉js引擎这些是密集阵列
#不过,在node.js上运行时似乎会产生不可忽略的效果
对于[0…数据大小]中的行
数据[行]=新数组();
对于[0…数据大小]中的列
数据[行][cols]=0
数据[0][0]=数据[0][data_SIZE-1]=数据[data_SIZE-1][0]=
数据[数据大小-1][数据大小-1]=种子;
h=500.0
边长=数据大小-1
而边长>=2
半边=边长/2
对于x英寸[0…数据大小-1],按边长
对于[0…数据大小-1]中的y,按边长
平均值=数据[x][y]+
数据[x+边长][y]+
数据[x][y+边长]+
数据[x+边长][y+边长]
平均值/=4.0;
数据[x+半边][y+半边]=
平均+数学随机()*(2*h)-h;
iters++
#console.log“A:”+x+“,“+y”
对于x英寸[0…数据大小-1],按半边
y=(x+半边)%sideLength
而y
JAVA
import java.util.Random;
类Gen{
公共静态void main(字符串参数[]){
身高(256+1);
身高(512+1);
基因高度(1024+1);
genHeight(2048+1);
身高(4096+1);
}
公共静态高度(内部sz){
long timeStart=System.currentTimeMillis();
int-iters=0;
最终整数数据_SIZE=sz;
最终双种子=1000.0;
双精度[]数据=新的双精度[数据大小][数据大小];
数据[0][0]=数据[0][data_SIZE-1]=数据[data_SIZE-1][0]=
数据[数据大小-1][数据大小-1]=种子;
双h=500.0;
随机r=新随机();
对于(int sideLength=DATA_SIZE-1;
边长>=2;
边长/=2,h/=2.0){
内半边=边长/2;
对于(int x=0;x暂时不要考虑Coffeescript,因为这不是问题的根源。当node运行它时,该代码只会被写入常规的旧javascript
就像其他javascript环境一样,node是单线程的。V8引擎速度非常快,但对于某些类型的应用程序,您可能无法超过jvm的速度
首先,我建议在转到CS之前,尝试直接在js中修改菱形算法。看看你能做什么样的速度优化
事实上,我现在对这个问题也有点感兴趣,我想看看如何做
编辑#2这是我的第二次重写,进行了一些优化,例如预填充数据数组。虽然速度没有明显加快,但代码更干净了一点
var makegrid = function(size){
size++; //increment by 1
var grid = [];
grid.length = size,
gsize = size-1; //frequently used value in later calculations.
//setup grid array
var len = size;
while(len--){
grid[len] = (new Array(size+1).join(0).split('')); //creates an array of length "size" where each index === 0
}
//populate four corners of the grid
grid[0][0] = grid[gsize][0] = grid[0][gsize] = grid[gsize][gsize] = corner_vals;
var side_length = gsize;
while(side_length >= 2){
var half_side = Math.floor(side_length / 2);
//generate new square values
for(var x=0; x<gsize; x += side_length){
for(var y=0; y<gsize; y += side_length){
//calculate average of existing corners
var avg = ((grid[x][y] + grid[x+side_length][y] + grid[x][y+side_length] + grid[x+side_length][y+side_length]) / 4) + (Math.random() * (2*height_range - height_range));
//calculate random value for avg for center point
grid[x+half_side][y+half_side] = Math.floor(avg);
}
}
//generate diamond values
for(var x=0; x<gsize; x+= half_side){
for(var y=(x+half_side)%side_length; y<gsize; y+= side_length){
var avg = Math.floor( ((grid[(x-half_side+gsize)%gsize][y] + grid[(x+half_side)%gsize][y] + grid[x][(y+half_side)%gsize] + grid[x][(y-half_side+gsize)%gsize]) / 4) + (Math.random() * (2*height_range - height_range)) );
grid[x][y] = avg;
if( x === 0) grid[gsize][y] = avg;
if( y === 0) grid[x][gsize] = avg;
}
}
side_length /= 2;
height_range /= 2;
}
return grid;
}
makegrid(256)
makegrid(512)
makegrid(1024)
makegrid(2048)
makegrid(4096)
var makegrid=函数(大小){
size++;//增加1
var网格=[];
网格长度=大小,
gsize=size-1;//在以后的计算中经常使用的值。
//设置网格阵列
var len=大小;
而(len--){
grid[len]=(新数组(大小+1).join(0).split(“”));//创建一个长度为“size”的数组,其中每个索引===0
}
//填充网格的四个角
网格[0][0]=网格[gsize][0]=网格[0][gsize]=网格[gsize][gsize]=角值;
var side_length=gsize;
而(边长>=2){
var half_side=数学楼层(边长/2);
//生成新的平方值
对于(var x=0;x如果你想在这样的算法中寻找性能,那么coffee/js和Java都是错误的语言。Javascript对于这样的问题尤其糟糕,因为它没有数组类型-数组只是散列映射,其中键必须是整数,这显然不会像真正的数组那么快ant将用C编写此算法,并从节点调用该算法(请参阅)。除非你真的擅长优化机器代码,否则好的C语言很容易超越任何其他语言。正如其他回答者所指出的,JavaScript的数组是你正在执行的操作类型的主要性能瓶颈。因为它们是动态的,访问元素自然要比使用Java的静态语言慢得多数组
好消息是,JavaScript中的静态类型数组有了一个新的标准,一些浏览器已经支持了该标准。虽然Node本身还不支持该标准,但您可以通过一个库轻松地添加它们:
安装后
var makegrid = function(size){
size++; //increment by 1
var grid = [];
grid.length = size,
gsize = size-1; //frequently used value in later calculations.
//setup grid array
var len = size;
while(len--){
grid[len] = (new Array(size+1).join(0).split('')); //creates an array of length "size" where each index === 0
}
//populate four corners of the grid
grid[0][0] = grid[gsize][0] = grid[0][gsize] = grid[gsize][gsize] = corner_vals;
var side_length = gsize;
while(side_length >= 2){
var half_side = Math.floor(side_length / 2);
//generate new square values
for(var x=0; x<gsize; x += side_length){
for(var y=0; y<gsize; y += side_length){
//calculate average of existing corners
var avg = ((grid[x][y] + grid[x+side_length][y] + grid[x][y+side_length] + grid[x+side_length][y+side_length]) / 4) + (Math.random() * (2*height_range - height_range));
//calculate random value for avg for center point
grid[x+half_side][y+half_side] = Math.floor(avg);
}
}
//generate diamond values
for(var x=0; x<gsize; x+= half_side){
for(var y=(x+half_side)%side_length; y<gsize; y+= side_length){
var avg = Math.floor( ((grid[(x-half_side+gsize)%gsize][y] + grid[(x+half_side)%gsize][y] + grid[x][(y+half_side)%gsize] + grid[x][(y-half_side+gsize)%gsize]) / 4) + (Math.random() * (2*height_range - height_range)) );
grid[x][y] = avg;
if( x === 0) grid[gsize][y] = avg;
if( y === 0) grid[x][gsize] = avg;
}
}
side_length /= 2;
height_range /= 2;
}
return grid;
}
makegrid(256)
makegrid(512)
makegrid(1024)
makegrid(2048)
makegrid(4096)
{Float32Array} = require 'typed-array'
genHeightField = (sz) ->
timeStart = new Date()
DATA_SIZE = sz
SEED = 1000.0
iters = 0
# Initialize 2D array of floats
data = new Array(DATA_SIZE)
for rows in [0...DATA_SIZE]
data[rows] = new Float32Array(DATA_SIZE)
for cols in [0...DATA_SIZE]
data[rows][cols] = 0
# The rest is the same...
17
75
417
1376
5461
19
47
215
855
3452