在我的代码中,我有一个包含一系列像素坐标的对象。此对象的性能至关重要,因为它在60fps游戏中使用,其输出不能始终被缓存。
经过实验和基准测试,在使用非类型化数组时,3D数组被证明是实现它的最快方法:
var PixelCollection = function() {
this.pixels = [];
};
PixelCollection.prototype = {
add: function(x, y) {
var pixels = this.pixels;
if (pixels[y]) {
pixels[y].push(x);
} else {
pixels[y] = [x];
}
},
each: function(callback) {
var pixels = this.pixels;
for (var y = 0, m = pixels.length; y < m; y++) {
var row = pixels[y];
if (row) {
for (var i = 0, mm = row.length; i < mm; i++) {
callback(row[i], y);
}
}
}
}
};
在某些情况下,对象速度不够快,所以我尝试使用2D数组进行Uint8Array
实现:
var WIDTH = 255;
var HEIGHT = 160;
PixelCollection = function() {
this.pixels = new Uint8Array(WIDTH * HEIGHT);
};
PixelCollection.prototype = {
add: function(x, y) {
this.pixels[WIDTH * y + x] = 1;
},
each: function(callback) {
var pixels = this.pixels;
for (var i = 0, m = pixels.length; i < m; i++) {
if (pixels[i]) {
callback(i % WIDTH, Math.floor(i / WIDTH));
}
}
}
}
这个比较慢。我认为它会更快,因为写入 - 并且从Uint8array
读取更快,但是因为我为每个PixelCollection对象创建了一个巨大的对象,所以检索像素要慢一些,因为迭代需要更长的时间所有像素。 (注意:我还尝试使用无类型数组执行上面的实现:它是 lot 更慢)
PixelCollection通常没有设置所有像素。但是,边界框可能会跨越整个画布,因此我需要使用这么大的缓冲区来创建数组。
虽然可能有办法解决这个问题。我可以创建一个大的共享缓冲区,并为每个PixelCollection使用字节偏移量。因此,当PixelCollection P1
占用100个字节时,PixelCollection P2
将从字节偏移量100开始。这会更有效地使用内存,但我需要跟踪每个PixelCollection使用的字节范围(这就是C调用&#34;指针&#34;?)。
恼人的部分:当P1
的边界框展开时,我需要转移P2
为P1
腾出空间。我需要为共享缓冲区设置一个安全的缓冲区大小,所以我需要安全地猜测它需要多少内存。
实现这一点是可能的,但这需要大量的时间,试验和错误。
所以在开始之前:这似乎是一个好方法吗?有没有更好或更简单的方法来做到这一点?您知道我可以从中学到的任何示例实现吗?
修改:I added a jsperf in case you want to try your hand at an optimization.
如果你有一个很好的优化想法,请添加到这个jsperf。
答案 0 :(得分:1)
慢一点我想你的意思是跑PixelCollection.each
?如果没有多少点设置为1,则第二个示例可能会更慢,因为它仍会检查所有可能的位置,而第一个仅通过添加的点运行。如果您真的想要不惜任何代价地获得每一个纳秒(在这种情况下是内存),那么您可以预先分配两个Uint8Array
中的最大大小,并分别跟踪大小。
var WIDTH = 255;
var HEIGHT = 160;
var PixelCollection = function() {
this.pixels.length = 0;
this.pixels.x = new Uint8Array(WIDTH * HEIGHT);
this.pixels.y = new Uint8Array(WIDTH * HEIGHT);
};
PixelCollection.prototype = {
add: function(x, y) {
this.pixels.x[this.pixels.length] = x;
this.pixels.y[this.pixels.length] = y;
this.pixels.length++;
},
each: function(callback) {
var pixels = this.pixels;
for (var i = 0; i < this.pixels.length; i++) {
callback(this.pixels.x[i], this.pixels.y[i]);
}
}
};
如果您知道PixelCollection将增加的数量限制,那么您可以减少内存使用量。您甚至可以将两个数组合并为一个交替x和y值的双倍长度。
但是,如果您希望能够删除单个点,这种方法会变得棘手,而且它不可能比使用@ Pudge601循环更改的第一种方法快得多。