54

今後のプロジェクトで実行することを考えているキャッシングについては、Java シリアライゼーションについて考えてきました。つまり、使用する必要がありますか?

ここ数年、さまざまな理由からカスタムのシリアライゼーションとデシリアライゼーション (Externalizable) を書いてきました。最近では、相互運用性がさらに問題になってきており、.Net アプリケーションと対話する必要性が予見できるので、プラットフォームに依存しないソリューションを使用することを考えました。

GPB を高性能に使用した経験のある人はいますか? 速度と効率の点で、Java のネイティブ シリアライゼーションと比べてどうですか? あるいは、検討する価値のある他のスキームはありますか?

4

8 に答える 8

61

プロトコル バッファと Java のネイティブ シリアライゼーションの速度を比較したことはありませんが、相互運用性に関しては、Java のネイティブ シリアライゼーションは絶対にダメです。また、ほとんどの場合、スペースの点でプロトコル バッファーほど効率的ではありません。もちろん、保存できるものや参照などに関しては、多少柔軟性があります。Protocol Buffers は、意図されたものに非常に優れており、ニーズに合っている場合は素晴らしいですが、相互運用性のために明らかな制限があります。 (と他のこと)。

私は最近、Java と .NET の Protocol Buffers ベンチマーク フレームワークを投稿しました。Java バージョンはメインの Google プロジェクト( benchmarks ディレクトリ内) にあり、.NET バージョンは私の C# ポート プロジェクトにあります。PB 速度と Java シリアライゼーション速度を比較したい場合は、同様のクラスを作成してベンチマークすることができます。ただし、相互運用性に関心がある場合は、ネイティブ Java シリアル化 (または .NET ネイティブ バイナリ シリアル化) について考え直すつもりはありません。

Protocol Buffers 以外にも、相互運用可能なシリアライゼーションのオプションがあります。ThriftJSON、およびYAMLが思い浮かびます。

編集: さて、相互運用性はそれほど重要ではないので、シリアル化フレームワークから必要なさまざまな品質をリストしてみる価値があります。考慮すべきことの 1 つはバージョン管理です。これは、PB が後方と前方の両方を適切に処理するように設計されているもう 1 つのことです (したがって、新しいソフトウェアは古いデータを読み取ることができ、その逆も可能です) - もちろん、提案されたルールに固執する場合:)

Java のパフォーマンスとネイティブのシリアライゼーションに注意を払ってみた結果、いずれにせよ PB の方が高速であることに驚かなかったでしょう。機会があれば、サーバー VM を使用してください。私の最近のベンチマークでは、サーバー VMはサンプル データのシリアライズとデシリアライズで2 倍以上高速であることが示されました。PB コードはサーバー VM の JIT に非常に適していると思います:)

2 つのメッセージ (1 つは 228 バイト、もう 1 つは 84750 バイト) をシリアライズおよびデシリアライズするサンプル パフォーマンス数値と同様に、サーバー VM を使用してラップトップで次の結果を得ました。

ファイル google_message1.dat を使用した Benchmarks.GoogleSize$SizeMessage1 のベンチマーク
バイト文字列にシリアル化: 30.16 秒で 2581851 回の繰り返し。18.613789MB/秒
バイト配列にシリアル化: 29.842 秒で 2583547 回の繰り返し。18.824497MB/秒
メモリ ストリームへのシリアル化: 30.125 秒で 2210320 回の反復。15.953759MB/秒
バイト文字列からデシリアライズ: 30.088 秒で 3356517 回の繰り返し。24.256632MB/秒
バイト配列からの逆シリアル化: 29.958 秒で 3356517 回の反復。24.361889MB/秒
メモリ ストリームから逆シリアル化: 29.821 秒で 2618821 回の反復。19.094952MB/秒

ファイル google_message1.dat を使用した Benchmarks.GoogleSpeed$SpeedMessage1 のベンチマーク
バイト文字列にシリアル化: 29.978 秒で 17068518 回の繰り返し。123.802124MB/秒
バイト配列にシリアル化: 30.043 秒で 17520066 回の繰り返し。126.802376MB/秒
メモリ ストリームへのシリアル化: 30.076 秒で 7736665 回の反復。55.93307MB/秒
バイト文字列からデシリアライズ: 30.073 秒で 16123669 回の繰り返し。116.57947MB/秒
バイト配列からの逆シリアル化: 30.109 秒で 16082453 回の繰り返し。116.14243MB/秒
メモリ ストリームからのデシリアライズ: 30.03 秒で 7496968 回の反復。54.283176MB/秒

ファイル google_message2.dat を使用した Benchmarks.GoogleSize$SizeMessage2 のベンチマーク
バイト文字列へのシリアル化: 30.034 秒で 6266 回の繰り返し。16.826494MB/秒
バイト配列へのシリアル化: 30.027 秒で 6246 回の繰り返し。16.776697MB/秒
メモリ ストリームへのシリアル化: 29.916 秒で 6042 回の反復。16.288969MB/秒
バイト文字列からの逆シリアル化: 29.819 秒で 4675 回の繰り返し。12.644595MB/秒
バイト配列からの逆シリアル化: 30.093 秒で 4694 回の繰り返し。12.580387MB/秒
メモリ ストリームからの逆シリアル化: 29.579 秒で 4544 回の反復。12.389998MB/秒

ファイル google_message2.dat を使用した Benchmarks.GoogleSpeed$SpeedMessage2 のベンチマーク
バイト文字列にシリアル化: 30.055 秒で 39562 回の繰り返し。106.16416MB/秒
バイト配列にシリアル化: 30.178 秒で 39715 回の繰り返し。106.14035MB/秒
メモリ ストリームへのシリアル化: 30.032 秒で 34161 回の反復。91.74085MB/秒
バイト文字列からの逆シリアル化: 29.794 秒で 36934 回の繰り返し。99.98019MB/秒
バイト配列からの逆シリアル化: 29.915 秒で 37191 回の繰り返し。100.26867MB/秒
メモリ ストリームからの逆シリアル化: 29.846 秒で 36237 回の繰り返し。97.92251MB/秒

「速度」対「サイズ」は、生成されたコードが速度またはコードサイズのどちらで最適化されているかです。(シリアル化されたデータはどちらの場合も同じです。多くのメッセージが定義されていて、コードに多くのメモリを使用したくない場合のために、「サイズ」バージョンが提供されています。)

ご覧のとおり、小さなメッセージの場合、非常に高速になる可能性があります。1 ミリ秒あたり500 を超える小さなメッセージがシリアル化または逆シリアル化されます。87K のメッセージでも、1 メッセージあたり 1 ミリ秒もかかりません。

于 2009-03-15T13:16:52.583 に答える
8

また、組み込みのJDKシリアル化のドロップイン代替品であるFSTもご覧ください。これは、より高速で出力が小さいはずです。

私が近年行った頻繁なベンチマークに関する生の見積もり:

100%=バイナリ/構造体ベースのアプローチ(例:SBE、fst-structs)

  • 不便
  • 後処理(レシーバー側で「実際の」オブジェクトを構築する)は、パフォーマンス上の利点を損なう可能性があり、ベンチマークに含まれることはありません。

〜10%-35%protobufおよび派生物

FSTやKRYOなどの約10%〜30%の高速シリアライザー

  • 便利な逆シリアル化されたオブジェクトは、追加の手動変換コードなしでほとんどの場合直接使用できます。
  • パフォーマンスを向上させることができます(アノテーション、クラス登録)
  • オブジェクトグラフのリンクを保持します(2回シリアル化されたオブジェクトはありません)
  • 環状構造を処理できます
  • 一般的なソリューションであるFSTは、JDKシリアル化と完全に互換性があります

〜2%-15%JDKシリアル化

〜1%-15%高速JSon(例:Jackson)

  • オブジェクトグラフを処理することはできませんが、Javaデータ構造のごく一部のみを処理できます
  • 参照の復元なし

0.001-1%完全グラフJSon / XML(JSON.ioなど)

これらの数値は、非常に大まかな桁違いの印象を与えることを目的としています。パフォーマンスは、シリアル化/ベンチマークされるデータ構造に大きく依存することに注意してください。したがって、単一の単純なクラスのベンチマークはほとんど役に立ちません(ただし、人気があります。たとえば、ユニコードを無視する、コレクションを無視する、..)。

も参照してください

http://java-is-the-new-c.blogspot.de/2014/12/a-persistent-keyvalue-server-in-40.html

http://java-is-the-new-c.blogspot.de/2013/10/still-using-externalizable-to-get.html

于 2012-12-06T22:17:33.830 に答える
7

高性能とはどういう意味ですか? ミリ秒のシリアル化が必要な場合は、最も単純なシリアル化アプローチを使用することをお勧めします。サブミリ秒が必要な場合は、バイナリ形式が必要になる可能性があります。10 マイクロ秒をはるかに下回る値が必要な場合は、カスタムのシリアル化が必要になる可能性があります。

シリアライゼーション/デシリアライゼーションのベンチマークはあまり見たことがありませんが、シリアライゼーション/デシリアライゼーションで 200 マイクロ秒未満をサポートするものはほとんどありません。

プラットフォームに依存しない形式はコストがかかります (ユーザー側の労力と待ち時間)。パフォーマンスまたはプラットフォームの独立性のどちらが必要かを決定する必要がある場合があります。ただし、必要に応じて切り替える構成オプションとして両方を使用できない理由はありません。

于 2009-03-15T13:53:26.583 に答える
6

速度と効率に関して PB とネイティブ Java シリアライゼーションを混同している場合は、PB を選択してください。

  • PB はそのような要因を達成するために設計されました。http://code.google.com/apis/protocolbuffers/docs/overview.htmlを参照してください
  • PB データは非常に小さいですが、Java シリアライゼーションは署名を含むオブジェクト全体を複製する傾向があります。レシーバーで裏返しに知っているにもかかわらず、クラス名、フィールド名...を常にシリアル化するのはなぜですか?
  • 言語発達全体について考えてみましょう。一方が Java を使用し、一方が C++ を使用すると、難しくなります。

一部の開発者は Thrift を提案していますが、「私は Google を信じている」ので、Google PB を使用します :-).. とにかく、一見の価値があります: http://stuartsierra.com/2008/07/10/thrift-vs-protocol -バッファ

于 2009-03-15T17:25:05.403 に答える
1

これがその日の思いがけない提案です:-)(あなたは私の頭の中で私が今試したいと思っていることを微調整しました)...

これを介してキャッシュソリューション全体を利用できる場合は、うまくいくかもしれません: Project Darkstar。これは非常に高性能なゲーム サーバーとして設計されており、特に読み取りが高速になるように設計されています (キャッシュに適しています)。Java と C の API があるので、Java でオブジェクトを保存し、C で読み返すことができると信じています (私がそれを見てから長い時間が経ちました)。

他に何もなければ、今日読むべき何かを与えるでしょう:-)

于 2009-03-15T15:36:35.180 に答える