6

この質問に触発されました。ProtoBuf、BinaryFormatter、Json.NET を比較する小さなベンチマーク プログラムを作成しました。ベンチマーク自体は、https: //github.com/sidshetye/SerializersCompare にある小さなコンソール ベースのものです。自由に追加/改善してください。新しいシリアライザーをミックスに追加するのは非常に簡単です。とにかく、私の結果は次のとおりです。

        Binary Formatter         ProtoBuf          Json.NET     ServiceStackJson   ServiceStackJSV
 Loop     Size:512 bytes    Size:99 bytes    Size:205 bytes      Size:205 bytes     Size:181 bytes
    1         16.1242 ms      151.6354 ms       277.2085 ms         129.8321 ms        146.3547 ms
    2          0.0673 ms        0.0349 ms         0.0727 ms           0.0343 ms          0.0370 ms
    4          0.0292 ms        0.0085 ms         0.0303 ms           0.0145 ms          0.0148 ms
    8          0.0255 ms        0.0069 ms         0.0017 ms           0.0216 ms          0.0129 ms
   16          0.0011 ms        0.0064 ms         0.0282 ms           0.0114 ms          0.0120 ms
   32          0.0164 ms        0.0061 ms         0.0334 ms           0.0112 ms          0.0120 ms
   64          0.0347 ms        0.0073 ms         0.0296 ms           0.0121 ms          0.0013 ms
  128          0.0312 ms        0.0058 ms         0.0266 ms           0.0062 ms          0.0117 ms
  256          0.0256 ms        0.0097 ms         0.0448 ms           0.0087 ms          0.0116 ms
  512          0.0261 ms        0.0058 ms         0.0307 ms           0.0127 ms          0.0116 ms
 1024          0.0258 ms        0.0057 ms         0.0309 ms           0.0113 ms          0.0122 ms
 2048          0.0257 ms        0.0059 ms         0.0297 ms           0.0125 ms          0.0121 ms
 4096          0.0247 ms        0.0060 ms         0.0290 ms           0.0119 ms          0.0120 ms
 8192          0.0247 ms        0.0060 ms         0.0286 ms           0.0115 ms          0.0121 ms

免責事項

  1. 上記の結果は Windows VM 内のものです。非常に短い間隔のストップウォッチ/タイマーの値は、ベアメタル OS と比較して 100% 正確ではない場合があります。したがって、上の表の非常に低い値は無視してください。

  2. ServiceStack の場合、スコアリングされた Json と JSV は 2 つの別々の実行から取得されました。それらは同じ基礎となる ServiceStack ライブラリを共有するため、次々に実行すると、次の実行の「コールド スタート」1 ループ スコアに影響します (「ウォーム スタート」高速です)。

BinaryFormatter はサイズが最大ですが、単一のシリアライゼーション => デシリアライゼーション ループでは最速です。ただし、シリアライゼーション => デシリアライゼーション コードをタイトにループすると、ProtoBuf は高速になります。

質問#1 : ProtoBuf が単一のシリアライゼーション => デシリアライゼーション ループでそれほど遅いのはなぜですか?

質問#2 : 実際的な観点から、その「コールド スタート」を乗り越えるために何ができるでしょうか? 少なくとも 1 つのオブジェクト (任意のタイプ) を実行しますか? すべての (重要な) オブジェクト タイプを実行しますか?

4

1 に答える 1

11

質問#1: ProtoBuf が単一のシリアライゼーション => デシリアライゼーション ループでそれほど遅いのはなぜですか?

モデルを分析して戦略を準備するには、膨大な量の作業が必要になるためです。生成された戦略を可能な限り高速にするために多くの時間を費やしましたが、メタプログラミング層の最適化を軽視した可能性があります. 最初のパスの時間を短縮するために、それを検討項目として追加できてうれしいです。もちろん、一方で、メタプログラミング層は、Json.NET の同等の前処理よりも 2 倍高速です ;p

質問 2: 実際的な観点から、「コールド スタート」を乗り越えるために何ができるでしょうか? 少なくとも 1 つのオブジェクトを (いつでも) 実行しますか? すべての (重要な) オブジェクト タイプを実行しますか?

さまざまなオプション:

  1. ビルドプロセスの一部として「プリコンパイル」ツールを使用して、コンパイルされたシリアライザーを、通常のように参照して使用できる別の完全に静的なコンパイル済み dll として生成します。その後、メタプログラミングはまったく発生しません。
  2. 起動時に「ルート」タイプについてモデルに明示的に伝え、の出力を保存しますCompile()

    static TypeModel serializer;
    ...
    RuntimeTypeModel.Default.Add(typeof(Foo), true);
    RuntimeTypeModel.Default.Add(typeof(Bar), true);
    serializer = RuntimeTypeModel.Default.Compile();
    

    (Compile()メソッドはルート型から分析し、必要に応じて追加の型を追加し、コンパイルされ生成されたインスタンスを返します)

  3. 起動時に「ルート」タイプについてモデルに明示的に伝え、「CompileInPlace()数回」呼び出します。CompileInPlace()モデルを完全に展開するわけではありませんが、1 つのレイヤーをコンパイルすると他のタイプがモデルに取り込まれるため、数回呼び出すだけでほとんどのベースをカバーできます。

    RuntimeTypeModel.Default.Add(typeof(Foo), true);
    RuntimeTypeModel.Default.Add(typeof(Bar), true);
    for(int i = 0 ; i < 5 ; i++) {
        RuntimeTypeModel.Default.CompileInPlace();
    }
    

これとは別に、おそらく次のことを行う必要があります。

  1. CompileInPlaceシナリオのモデルを完全に展開するメソッドを追加する
  2. メタプログラミング層の最適化に時間を費やす

Compile最終的な考え:とここの主な違いは、CompileInPlaceいくつかのタイプを追加するのを忘れた場合に何が起こるかです。CompileInPlace既存のモデルに対して機能するため、後で新しい型を (暗黙的または明示的に) 追加することができます。Compileより厳格です: それを介して型を生成すると、それは修正され、コンパイル時に推定できる型のみを処理できます。

于 2012-12-06T12:18:18.387 に答える