Node.jsでのオブジェクトのクローン作成:より速く、より深く、より柔軟に!

少し前、 idoroshenkoの記事「なぜevalが必ずしも悪いわけではない」を読んだ後、オブジェクトのクローンを作成するために関数の本体を生成するアプローチを使用できるかどうか疑問に思いました。 このために小さなライブラリを作成しました。 ベンチマークは信じられないほどの結果をもたらしましたが、このアプローチの適用可能性は、同一のオブジェクトのマルチクローニングにのみ制限されていました。



したがって、質問がありました:v8には、隠されたクラスの複数の再作成に関連するコストを回避する他の方法は本当にありませんか? 結局のところ、これはオブジェクトを複製する際のリソースの主な浪費です。 判明したように、実際にはそのような可能性があります。v8自体では、オブジェクトにはv8 :: Object :: Cloneメソッドがあります。 このメソッドは、広義のオブジェクト、つまりオブジェクト自体、配列、日付、正規表現、関数などを複製しますが、非標準プロパティ(配列の名前付きプロパティなど)を含むすべてのプロパティを保持します。隠されていても。



小さな問題が1つだけありました。 このメソッドはnode.jsの腸内でのみ使用され、javascriptに対して外部に開かれていませんでした。



考え直すことなく、c ++での拡張機能の作成に関するnode.jsのドキュメントを読みこの機能を単純に拡張するモジュールの試用版を 作成ました



さまざまなオブジェクトの加速を約10〜100倍受け取ったので、この手法には大きな可能性があることに気付き、 node-v8-clonenpm )モジュールに実装し始めました。 TDDおよびベンチマーク駆動型開発。 これにより、問題の開発および修正中に速度を監視し、最適化中に回帰を監視することができました。 同時に、ベンチマークとテストの準備が整ったため、モジュールを他のモジュールと比較することにしました。





クローニング品質



目標の1つは、最高のクローン品質を達成することでした。 クローン作成プロセスに十分な不快な状況を思い付くために、私は自分の想像力を利用しなければなりませんでした。 これらには、たとえば、関数、クロージャー、引数、現在の状態の正規表現、ユーザーが追加したプロパティが含まれます。 私のモジュールは、次のようなこれらの状況を扱います。





ここでは、競合他社の状況を評価できます



非常に価値があると思いました。



スピード



高品質のクローン作成がサポートされているため、速度が低下したはずだと考えるのは自然なことです。 そして、速度は本当に低下しましたが、ほとんどの状況でnode-v8-cloneが優位性を失うほどではありませんでした。

たとえば、100個の要素を持つオブジェクトのサーフェスクローニングの結果を次に示します{'_0': '_0', ..., '_99': '_99'}



(1秒あたりの操作数):



900行を含む4レベルのネストにある500のネストされたアレイのディープクローニング



しかし、小さな配列では、事態はやや悪化します。 これは、c ++モジュールにアクセスするための高コストに影響を与えるため、forなどの単純なアルゴリズムに利点があります。





すべてのベンチマーク結果。



次は何ですか



node.jsバッファーの複製を修正しようとしています。 現在、それらはクローンを作成しています(a!== b)が、同じメモリ領域を指し、その内容はまだ接続されています。

引数の複製を修正したいと思います。 関数に引数がある場合、引数オブジェクトは関数のコンテキストに関連付けられ、複製されると、それらも関連します。

ファイル記述子、モジュール、タイマーなど、さらにトリッキーな受信データを考え出したいと思います...本当にそれらを複製できるとは思いませんが、少なくともこのモジュールがどのように動作するかを理解したいと思います。



フィードバック、提案、バグ、パッチを歓迎します。 さて、 GitHubフォークしてください :)



All Articles