mat*_*t b 14 performance node.js coffeescript
我与node.js的尝试建立一些服务器端逻辑,并实现了一个版本中描述的菱形方算法的这里在CoffeeScript中和Java.鉴于我对node.js和V8性能的所有赞誉,我希望node.js不会落后于java版本.
但是在4096x4096地图上,Java在1s以下完成,但node.js/coffeescript在我的机器上需要20多秒...
这些是我的全部结果.x轴是网格大小.对数和线性图表:


这是因为我的coffeescript实现有问题,还是这只是node.js的本质?
genHeightField = (sz) ->
timeStart = new Date()
DATA_SIZE = sz
SEED = 1000.0
data = new Array()
iters = 0
# warm up the arrays to tell the js engine these are dense arrays
# seems to have neligible effect when running on node.js though
for rows in [0...DATA_SIZE]
data[rows] = new Array();
for cols in [0...DATA_SIZE]
data[rows][cols] = 0
data[0][0] = data[0][DATA_SIZE-1] = data[DATA_SIZE-1][0] =
data[DATA_SIZE-1][DATA_SIZE-1] = SEED;
h = 500.0
sideLength = DATA_SIZE-1
while sideLength >= 2
halfSide = sideLength / 2
for x in [0...DATA_SIZE-1] by sideLength
for y in [0...DATA_SIZE-1] by sideLength
avg = data[x][y] +
data[x + sideLength][y] +
data[x][y + sideLength] +
data[x + sideLength][y + sideLength]
avg /= 4.0;
data[x + halfSide][y + halfSide] =
avg + Math.random() * (2 * h) - h;
iters++
#console.log "A:" + x + "," + y
for x in [0...DATA_SIZE-1] by halfSide
y = (x + halfSide) % sideLength
while y < DATA_SIZE-1
avg =
data[(x-halfSide+DATA_SIZE-1)%(DATA_SIZE-1)][y]
data[(x+halfSide)%(DATA_SIZE-1)][y]
data[x][(y+halfSide)%(DATA_SIZE-1)]
data[x][(y-halfSide+DATA_SIZE-1)%(DATA_SIZE-1)]
avg /= 4.0;
avg = avg + Math.random() * (2 * h) - h;
data[x][y] = avg;
if x is 0
data[DATA_SIZE-1][y] = avg;
if y is 0
data[x][DATA_SIZE-1] = avg;
#console.log "B: " + x + "," + y
y += sideLength
iters++
sideLength /= 2
h /= 2.0
#console.log iters
console.log (new Date() - timeStart)
genHeightField(256+1)
genHeightField(512+1)
genHeightField(1024+1)
genHeightField(2048+1)
genHeightField(4096+1)
Run Code Online (Sandbox Code Playgroud)
import java.util.Random;
class Gen {
public static void main(String args[]) {
genHeight(256+1);
genHeight(512+1);
genHeight(1024+1);
genHeight(2048+1);
genHeight(4096+1);
}
public static void genHeight(int sz) {
long timeStart = System.currentTimeMillis();
int iters = 0;
final int DATA_SIZE = sz;
final double SEED = 1000.0;
double[][] data = new double[DATA_SIZE][DATA_SIZE];
data[0][0] = data[0][DATA_SIZE-1] = data[DATA_SIZE-1][0] =
data[DATA_SIZE-1][DATA_SIZE-1] = SEED;
double h = 500.0;
Random r = new Random();
for(int sideLength = DATA_SIZE-1;
sideLength >= 2;
sideLength /=2, h/= 2.0){
int halfSide = sideLength/2;
for(int x=0;x<DATA_SIZE-1;x+=sideLength){
for(int y=0;y<DATA_SIZE-1;y+=sideLength){
double avg = data[x][y] +
data[x+sideLength][y] +
data[x][y+sideLength] +
data[x+sideLength][y+sideLength];
avg /= 4.0;
data[x+halfSide][y+halfSide] =
avg + (r.nextDouble()*2*h) - h;
iters++;
//System.out.println("A:" + x + "," + y);
}
}
for(int x=0;x<DATA_SIZE-1;x+=halfSide){
for(int y=(x+halfSide)%sideLength;y<DATA_SIZE-1;y+=sideLength){
double avg =
data[(x-halfSide+DATA_SIZE-1)%(DATA_SIZE-1)][y] +
data[(x+halfSide)%(DATA_SIZE-1)][y] +
data[x][(y+halfSide)%(DATA_SIZE-1)] +
data[x][(y-halfSide+DATA_SIZE-1)%(DATA_SIZE-1)];
avg /= 4.0;
avg = avg + (r.nextDouble()*2*h) - h;
data[x][y] = avg;
if(x == 0) data[DATA_SIZE-1][y] = avg;
if(y == 0) data[x][DATA_SIZE-1] = avg;
iters++;
//System.out.println("B:" + x + "," + y);
}
}
}
//System.out.print(iters +" ");
System.out.println(System.currentTimeMillis() - timeStart);
}
}
Run Code Online (Sandbox Code Playgroud)
Tre*_*ham 11
正如其他回答者所指出的那样,JavaScript的数组是您正在进行的操作类型的主要性能瓶颈.因为它们是动态的,所以访问元素比使用Java的静态数组要慢得多.
好消息是,JavaScript中存在一种新兴的静态类型数组标准,某些浏览器已经支持这种标准.虽然Node本身尚不支持,但您可以使用库轻松添加它们:https://github.com/tlrobinson/v8-typed-array
typed-array通过npm 安装后,这是我修改后的代码版本:
{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...
Run Code Online (Sandbox Code Playgroud)
其中的关键是宣言data[rows].
使用该行data[rows] = new Array(DATA_SIZE)(基本上等同于原始行),我得到基准数字:
17
75
417
1376
5461
Run Code Online (Sandbox Code Playgroud)
随着线路data[rows] = new Float32Array(DATA_SIZE),我得到了
19
47
215
855
3452
Run Code Online (Sandbox Code Playgroud)
因此,一个小的改变可以将运行时间减少大约1/3,即速度提高50%!
它仍然不是Java,但它是一个相当大的改进.期待未来版本的Node/V8进一步缩小性能差距.
警告:必须提到的是,普通的JS数字是双精度的,即64位浮点数.Float32Array因此,使用会降低精度,使其成为苹果和橙子的比较 - 我不知道使用32位数学有多少性能提升,以及更快的数组访问有多少.A Float64Array 是 V8规范的一部分,但尚未在v8类型的数组库中实现.)
| 归档时间: |
|
| 查看次数: |
2878 次 |
| 最近记录: |