8

ピクセルごとにキャンバス要素に画像を描画する関数を書いています。関数の処理に以前よりも突然時間がかかるポイントがあることに気付きました。具体的には、338x338 ピクセルのキャンバスから 339x339 ピクセルのキャンバスに移行するときです。

似たような関数を jsfiddle に入れても、同じ結果が得られます。338x338 の配列を処理する while ループには、約 1 秒かかります。339x339 の配列には約 6 ~ 7 秒かかります。24 ~ 25 秒。

これは Chrome で発生しています。Firefoxでは、両方とも約かかります。16秒。

これがフィドルです: http://jsfiddle.net/8pb89/5/

コードは次のようになります。

var ary1 = [];
var ary2 = [];
var mapData = {};
var colorMatrix = {};

for (var i = 0; i < (338 * 338); i++) {
    ary1.push([i, i + 2]);
}

for (var i = 0; i < (339 * 339); i++) {
    ary2.push([i, i + 2]);
}

//Light operation
function test(i, j) {
    return Math.floor((i * j + i + j) / j);
}

//Heavy operation on objects
function calcTest(ary){
    var point = ary.splice(0, 1);
    var i = point[0];
    var j = point[1];

    if (!mapData[i]) {
        mapData[i] = [];
    }
    if (!mapData[i][j]) {
        mapData[i][j] = [];
    }

    mapData[i][j]["one"] = test(i, j);
    mapData[i][j]["two"] = test(i, j);

    colorMatrix[mapData[i][j]["two"]] = mapData[i][j]["one"];

}

var len = ary1.length;
var start = new Date().getTime();

while (len--) {
    calcTest(ary1);
}

var end = new Date().getTime();
var time = end - start;
alert('Execution for 338x338: ' + time);

var len2 = ary2.length;
obj = {};
obj2 = {};

start = new Date().getTime();
while (len2--) {
    calcTest(ary2);
}
end = new Date().getTime();
time = end - start;
alert('Execution for 339x339: ' + time);

これは Chrome の JavaScript のメモリの問題ですか、それともオブジェクトに何か問題がありますか? この長い処理時間を回避する方法はありますか?

4

2 に答える 2

1

以下のどちらか、もしくは両方だと思います。

  • Chrome は、基になるハッシュテーブルのサイズを ~ の間のどこかでサイズ変更してい338 * 338ます339 * 339
  • ガベージ コレクションは、同じ時間枠で行われています。

これはメモリの問題だと思います。

于 2013-07-17T20:05:46.317 に答える
1

SPLICE 操作が実際に何をしているのかを考えてみましょう。この配列をスプライシングしてみましょう:

[0,1,2,3,4,5]

私はしなければならないでしょう:

STORE the 0
READ the 1, WRITE to where the 0 was
READ the 2, WRITE to where the 1 was
READ the 3, WRITE to where the 2 was
READ the 4, WRITE to where the 3 was
READ the 5, WRITE to where the 4 was
DELETE the 5

これは 12 の操作です (6 アイテムの配列で)... 配列ははるかに大きく (100k アイテム以上) です...そして、それらを反復処理し、徐々に減らしていきます。私はあなたがあなたのコードで要求している約 260 億の計算を行います!!!

while ループをテスト内に配置し、SPLICE 関数を使用しないようにコードをリファクタリングしました。マシンでテストを 23 ミリ秒と 25 ミリ秒に短縮しました (テストと同じ結果が得られました)。 3599ms と 19464ms - 500 倍近く効率的です :)

このコードには他にも多くの問題がありますが、これが最大の問題の核心に迫っています。

var ary1 = [];
var ary2 = [];
var mapData = {};
var colorMatrix = {};

for (var i = 0; i < (338 * 338); i++) {
    ary1.push([i, i + 2]);
}

for (var i = 0; i < (339 * 339); i++) {
    ary2.push([i, i + 2]);
}

//Light operation
function test(i, j) {
    return Math.floor((i * j + i + j) / j);
}

//Heavy operation on objects
function calcTest(ary){
    for (index=ary.length-1;index>=0;index--){
        var point=ary[index];

        var i = point[0];
        var j = point[1];

        if (!mapData[i]) {
            mapData[i] = [];
        }
        if (!mapData[i][j]) {
            mapData[i][j] = [];
        }

        mapData[i][j]["one"] = test(i, j);
        mapData[i][j]["two"] = test(i, j);

        colorMatrix[mapData[i][j]["two"]] = mapData[i][j]["one"];
    }
}

//I'm only putting the following lines in first to show that the first
//Operation takes longer by populating the mapData and colorMatrix arrays
//If you delete the next two lines you'll find that the 339 option takes
//less time than the 338 (because it's going second!)
calcTest(ary1);
calcTest(ary2);

var start = new Date().getTime();
calcTest(ary1);
var end = new Date().getTime();
var time = end - start;
alert('Execution for 338x338: ' + time);

start = new Date().getTime();
calcTest(ary2);
end = new Date().getTime();
time = end - start;
alert('Execution for 339x339: ' + time);
于 2013-07-19T10:33:59.163 に答える