web-dev-qa-db-ja.com

.NETでの高速でコンパクトなオブジェクトのシリアル化

Mono サーバーとSilverlightクライアントの間のネットワークを介して通信するために、オブジェクトのシリアル化を使用します。サーバーは複数のリアルタイムゲームをホストするため、シリアル化はスペース効率が良く、非常に高速であることが非常に重要です。

どのテクニックを使用すればよいですか? BinaryFormatterは、このアプリケーション内で必要とされないシリアル化されたクラス(バージョン、カルチャ、クラス名、プロパティ名など)に多くのオーバーヘッドを追加します。

このスペースをより効率的にするにはどうすればよいですか?

57
Dennis Kempin

Protocol Buffers を使用できます。シリアル化コードをすべてBinaryFormatterからProtocol Buffersに圧縮して変更し、非常に良い結果を得ています。時間と空間の両方でより効率的です。

Jon SkeetMarc Gravell による2つの.NET実装があります。

Update:公式の.NET実装は here にあります。

Northwindデータセットに基づいて、いくつかの 主要な.NETシリアライザーのベンチマーク を使用できます。

Northwind .NET serialization benchmarks

@marcgravellバイナリprotobuf-netは、BCLで利用可能なMicrosoftの最速シリアライザー(XML DataContractSerializer)よりも約7x速いベンチマークされた最速の実装です。

また、いくつかのオープンソースの高性能.NETテキストシリアライザーも保守しています。

  • JSV TypeSerializer DataContractSerializerよりも3.1倍速い、コンパクトでクリーンなJSON + CSVのような形式
  • JsonSerializer も2.6倍高速です。
52
mythz

著者として、 protobuf-net ;を試してみてください。 Mono 2.0と Silverlight 2.0の両方のバイナリが付属しており、 高速で効率的 です。何か問題があれば、私にメールを送ってください(私のStack Overflowプロファイルを参照してください)。サポートは無料です。

Jonのバージョン(以前に受け入れられた回答を参照)も非常に優れていますが、protobuf-netバージョンのIMOはC#の方が慣用的です-Jonは、C#をJavaと話している場合に理想的であるため、両端に同様のAPIがあります。

28
Marc Gravell

同様の問題がありましたが、.NETを使用しています。できる限り迅速かつ簡単にデータをインターネット経由で送信したかったのです。十分に最適化されるものが見つからなかったため、 NetSerializer という名前の独自のシリアライザーを作成しました。

NetSerializerには制限がありますが、私のユースケースには影響しませんでした。そして、私はしばらくの間ベンチマークを行っていませんが、私が見つけた他のどの製品よりもはるかに高速でした。

MonoやSilverlightで試したことはありません。 Monoで動作するとは思いますが、Silverlight上のDynamicMethodsのサポートレベルがわからないのです。

8
Tomba

JSONを使用してみてください。プロトコルバッファほど効率的な帯域幅ではありませんが、Wiresharkなどのツールを使用してメッセージを監視する方がはるかに簡単です。これは、問題のデバッグに役立ちます。 .NET 3.5にはJSONシリアライザーが付属しています。

5
Pablote

DeflateStreamまたはGZipStreamを介してデータを渡し、送信前にデータを圧縮できます。これらのクラスはSystem.IO.Compression名前空間に存在します。

4
Sean

ファイルに保存するという非常に似た問題がありました。ただし、実際にはリモーティング用に設計されているため、ネットワーク上で次のものも使用できます。

解決策は、Simon Hewittのライブラリを使用することです-。NETでのシリアル化の最適化-パート2を参照してください。

パート1 記事の状態(太字は私の強調です): "...大量のデータに.NETリモーティングを使用したことがある場合、スケーラビリティに問題があることがわかります。 。少量のデータの場合は十分に機能しますが、大量のデータは大量のCPUとメモリを消費し、大量のデータを送信用に生成します。メモリ不足の例外で失敗する可能性があります。実際にシリアル化を実行するのにかかる時間にも大きな問題があります-大量のデータにより、アプリでの使用が不可能になる可能性があります....」

特定のアプリケーションでも同様の結果が得られ、40分の1の節約と20分の1の読み込み(数分から数秒)が実現しました。シリアル化されたデータのサイズも大幅に削減されました。正確には覚えていませんが、少なくとも2〜3回は覚えていました。

始めるのはとても簡単です。ただし、1つの落とし穴があります。非常に高いレベルのデータ構造に対してのみ.NETシリアル化を使用し(シリアル化/逆シリアル化を開始するため)、次に、最上位レベルのデータ構造内のフィールドに対してシリアル化/逆シリアル化関数を直接呼び出します。そうしないと、高速化は行われません...たとえば、特定のデータ構造(たとえばGeneric.List)がライブラリでサポートされていない場合、代わりに.NETシリアル化が使用され、これはノーです。代わりに、クライアントコード(または同様の)でリストをシリアル化します。例については、「「これは私たち自身のエンコーディングです。」をご覧ください。以下にリストされているのと同じ機能で。

参考: 私のアプリケーションからのコード -「注:これは、組み込みの.NETを使用する唯一の場所です...」を参照してください。

3
Peter Mortensen

圧縮されたデータサイズに焦点を当て、これまでで最高の圧縮を提供するBOISを試すことができます。 (私はまだより良い最適化を見ていません。)

https://github.com/salarcode/Bois

2
Salar