2016-07-16 1 views
6

Stringメソッドのプロトタイプをいくつかのユーティリティメソッドで拡張したかったのです。それはうまくいったが、パフォーマンスは驚くほど低かった。文字列を関数に渡すことは、同じことをしているString.prototypeメソッドをオーバーライドするよりも10倍高速です。これが実際に起こることを確かめるために、私は非常に単純なcount()関数とそれに対応するメソッドを作成しました。 String.prototypeのパフォーマンスを拡張すると、関数呼び出しが10倍高速になることがわかります。

は(私が試した、と方法の3つのバージョンを作成しました。)

function count(str, char) { 
    var n = 0; 
    for (var i = 0; i < str.length; i++) if (str[i] == char) n++; 
    return n; 
} 

String.prototype.count = function (char) { 
    var n = 0; 
    for (var i = 0; i < this.length; i++) if (this[i] == char) n++; 
    return n; 
} 

String.prototype.count_reuse = function (char) { 
    return count(this, char) 
} 

String.prototype.count_var = function (char) { 
    var str = this; 
    var n = 0; 
    for (var i = 0; i < str.length; i++) if (str[i] == char) n++; 
    return n; 
} 

// Here is how I measued speed, using Node.js 6.1.0 

var STR ='0110101110010110100111010011101010101111110001010110010101011101101010101010111111000'; 
var REP = 1e3//6; 

console.time('func') 
for (var i = 0; i < REP; i++) count(STR,'1') 
console.timeEnd('func') 

console.time('proto') 
for (var i = 0; i < REP; i++) STR.count('1') 
console.timeEnd('proto') 

console.time('proto-reuse') 
for (var i = 0; i < REP; i++) STR.count_reuse('1') 
console.timeEnd('proto-reuse') 

console.time('proto-var') 
for (var i = 0; i < REP; i++) STR.count_var('1') 
console.timeEnd('proto-var') 

結果:

func: 705 ms 
proto: 10011 ms 
proto-reuse: 10366 ms 
proto-var: 9703 ms 

あなたは差は劇的で見ることができるように。

メソッド呼び出しのパフォーマンスが無視できるほど遅く、関数コード自身がメソッドの処理速度が遅いことがわかります。

function count_dummy(str, char) { 
    return 1234; 
} 

String.prototype.count_dummy = function (char) { 
    return 1234; // Just to prove that accessing the method is not the bottle-neck. 
} 

console.time('func-dummy') 
for (var i = 0; i < REP; i++) count_dummy(STR,'1') 
console.timeEnd('func-dummy') 

console.time('proto-dummy') 
for (var i = 0; i < REP; i++) STR.count_dummy('1') 
console.timeEnd('proto-dummy') 

console.time('func-dummy') 
for (var i = 0; i < REP; i++) count_dummy(STR,'1') 
console.timeEnd('func-dummy') 

結果:

func-dummy: 0.165ms 
proto-dummy: 0.247ms 

(1E8のような)巨大な繰り返しでメソッドを試作が機能よりも10倍の倍遅くであると証明する、これはこのケースでは無視することができます。

var A = { count: 1234 }; 

function getCount(obj) { return obj.count } 

A.getCount = function() { return this.count } 

console.time('func') 
for (var i = 0; i < 1e9; i++) getCount(A) 
console.timeEnd('func') 

console.time('method') 
for (var i = 0; i < 1e9; i++) A.getCount() 
console.timeEnd('method') 

結果::

func: 1689.942ms 
method: 1674.639ms 

あなたが関数に渡したり、メソッドを呼び出したときに、単純な汎用オブジェクトがほぼ同じ行うため

このすべては、唯一のStringオブジェクトに関連している可能性があり私はStackoverflowとbingingで検索してきましたが、「名前空間を汚染するためStringまたはArrayを拡張しないでください」という推奨事項(私の特定のプロジェクトでは問題ではない)は、メソッドの実行に関連するものは何も見つかりませんfunctioと比較してns。だから、私は単に、追加されたメソッドのパフォーマンス低下のためにStringオブジェクトを拡張することを忘れてはならないのでしょうか?

+0

感謝しますが:

その後、あなたの実装を修正。新しいインスタンスを取得します。 BTWの結果は同じです。 –

答えて

5

厳密なモードを使用していないため、メソッド内のthisの値をプリミティブな文字列ではなくStringインスタンスにキャストする必要があります。

var STR = new String('01101011…')で測定を繰り返すことで確認できます。あなたは最後の実装は遠くあなたが機能を持つオブジェクトを交換して、プロトタイプのメソッドを追加することができますprototype` `からであるなら、あなたの情報のため

String.prototype.count = function (char) { 
    "use strict"; 
    var n = 0; 
    for (var i = 0; i < this.length; i++) 
     if (this[i] == char) 
      n++; 
    return n; 
}; 
+1

それは動作しますが、私には意味がありません!したがって私は新しい質問を追加しました:http://stackoverflow.com/questions/38411552/why-use-strict-improves-performance-10x-in-this-example – exebook

+2

@exebook:私が言ったように、控えめなモードは 'this '値をオブジェクトに渡すので、すべての呼び出しで' String'インスタンスを作成する必要があります。これは、あなたのような単純なメソッドのオーバーヘッドです – Bergi

関連する問題