![](/img/trans.png)
[英]memory leak in JavaScript (WebWorker, Canvas, IndexedDB)
[英]Webworker canvas performance terrible
我正在尝试使用网络工作者来渲染动画mandelbrot缩放器的部分帧,因为其中涉及大量计算,并且由于可以轻松地将其拆分为多个块,因此这对于并行处理而言应该是理想的情况。
但是,无论我尝试什么,我都无法获得任何性能来回报工人使用的额外CPU。 与非工作版本相比,在Chrome浏览器中,我的基准测试要慢一些,而在Firefox中,它的基准测试要慢得多。
我的猜测是,将图像数据传输到网络工作者的成本非常高,我尝试仅接收原始数据并将其用于渲染帧,但是结果却几乎相同。 我认为这不是向工作人员发送和接收图像数据的理想方式(实际上我只需要接收它,但是我无法在工作人员中创建可直接用于画布的缓冲区) 。 因此,发送任何数量的数据都会造成真正的瓶颈。
亲爱的stackoverflow,请帮助我回答以下两个问题:我在这里做错了什么,可以改进什么?
可以在此处找到针对工作人员的演示,并且可以在jsfiddle上找到非工作人员版本以供参考。
代码如下:
"use strict";
/*global $*/
$(function() {
var mandelbrot = new Mandelbrot();
});
var Mandelbrot = function() {
// set some values
this.width = 500;
this.height = 500;
this.x_center = -1.407566731001088;
this.y_center = 2.741525895538953e-10;
this.iterations = 250;
this.escape = 4,
this.zoom = 10;
this.count = 0;
this.worker_size = 10;
this.received = 0;
this.refresh = true;
//let's go - create canvas, image data and workers
this.init();
//start animation loop
this.animate();
};
Mandelbrot.prototype = {
init: function() {
var self = this;
//create main canvas and append it to div
var container = $("#content");
this.canvas = document.createElement("canvas");
this.canvas.width = this.width;
this.canvas.height = this.height;
container.append(this.canvas);
//create imagedata
this.context = this.canvas.getContext("2d");
this.image = this.context.getImageData(0, 0, this.width, this.height);
this.data = new Int32Array(this.image.data.buffer);
//create imagedata for webworkers
this.worker_data = this.context.getImageData(0, 0, this.width, this.height / this.worker_size);
//create webworkers drop them in array
this.pool = [];
for (var i = 0; i < this.worker_size; i++) {
this.pool[i] = new Worker("js/worker.js");
this.pool[i].idle = true;
this.pool[i].id = i;
//on webworker finished
this.pool[i].onmessage = function(e) {
self.context.putImageData(e.data, 0, self.height / self.worker_size * e.target.id);
self.received++;
};
}
},
iterate: function() {
for (var i = 0; i < this.pool.length; i++) {
this.pool[i].postMessage({
image: this.worker_data,
id: this.pool[i].id,
worker_size: this.worker_size,
width: this.width,
height: this.height,
x_center: this.x_center,
y_center: this.y_center,
iterations: this.iterations,
escape: this.escape,
zoom: this.zoom
});
}
},
animate: function() {
requestAnimationFrame(this.animate.bind(this));
//poor man's benchmark over 250 frames
if (this.count === 0) {
console.time("timer");
}
if (this.count === 250) {
console.timeEnd("timer");
}
//refresh at init, then refresh when all webworkers are done and reset
if (this.received === this.worker_size | this.refresh) {
this.received = 0;
this.refresh = false;
this.count++;
this.zoom *= 0.95;
this.iterate();
}
}
};
和worker.js:
self.onmessage = function(e) {
"use strict";
var x_step = e.data.zoom / e.data.width;
var y_step = e.data.zoom / e.data.height;
var y_start = e.data.height / e.data.worker_size * e.data.id;
var y_end = e.data.height / e.data.worker_size;
var data = new Int32Array(e.data.image.data.buffer);
for (var y = 0; y < y_end; y++) {
var iy = e.data.y_center - e.data.zoom / 2 + (y + y_start) * y_step;
for (var x = 0; x < e.data.width; x++) {
var rx = e.data.x_center - e.data.zoom / 2 + x * x_step;
var zx = rx;
var zy = iy;
var zx2 = 0;
var zy2 = 0;
for (var i = 0; zx2 + zy2 < e.data.escape && i < e.data.iterations; ++i) {
zx2 = zx * zx;
zy2 = zy * zy;
zy = (zx + zx) * zy + iy;
zx = zx2 - zy2 + rx;
}
data[y * e.data.width + x] = (255 << 24) | (i << 16) | (i << 8) | i;
}
}
self.postMessage(e.data.image);
};
问题是您要遍历父图片中的每个像素。 如果将迭代限制为两个图像中较小的一个,则速度会更快。 另外,如果平铺图形,则可以在单独的Web工作人员中处理每个平铺,从而增加了图像各部分的码垛。 我写了这个: http : //robertleeplummerjr.github.io/CanvasWorker/正是您想要的。
我实际上在这个实验上尝试了同样的事情,这是一个位移过滤器:
http://www.soundstep.com/blog/experiments/displacement-js/heart/ http://www.soundstep.com/blog/2012/04/25/javascript-displacement-mapping/
我在过滤器中创建了一个工作程序,并在将它们发布回主应用程序之前一起计算了像素。 基本上迭代工作人员内部的所有像素。
在工作程序之前,我有一个循环4 getImageData,这不能在工作程序中完成。 无论如何,Chrome上的CPU占用率都约为15%。
因此,总的来说,没有工作人员,我可以获得70%的CPU,而有工作人员则可以达到90%的CPU。
我想在工作程序中无法执行的操作,例如“ getImageData”和“ putImageData”,加上拥有工作程序本身的事实,比没有工作程序需要更多的CPU。
如果我们能够发送其他类型的数据,那么可以在工作程序中执行getImageData和putImageData可能会更好。
不确定还有另一种发送和接收字节来处理和重构画布内容的方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.