32

C/C++ 対 C#/Java のパフォーマンスに関する質問は十分に検討されていると思いました。つまり、VM 言語が必ずしも「シリコンに近い」言語よりも遅いというわけではないことを示唆する十分な証拠を読んだということです。主な理由は、静的にコンパイルされた言語ではできない最適化を JIT コンパイラが実行できるためです。

しかし、私は最近、Java ベースの高頻度取引は常に C++ に打ち負かされ、そのような状況にあったと主張する人物から履歴書を受け取りました。

求人サイトをざっと見てみると、実際に HFT の応募者には C++ の知識が必要であることがわかります。Wilmottフォーラムを見ると、すべての実務家が C++ について話していることがわかります。

これが事実である特定の理由はありますか?現代の金融ビジネスはいくぶん複雑であるため、型安全性、マネージ メモリ、豊富なライブラリを備えた VM 言語が好まれると考えていたでしょう。その分、生産性は高くなります。さらに、JIT コンパイラーはますます良くなっています。プログラムの実行中に最適化を行うことができるため、その実行時の情報を使用して、管理されていないプログラムのパフォーマンスを打ち負かしていると思います。

おそらく、彼らは重要な部分を C++ で書き、管理された環境 (P/Invoke など) からそれらを呼び出しているのでしょうか? それは可能ですか?

最後に、これの中心的な質問の経験がある人はいますか?それが、この分野で管理されていないコードが管理されているコードよりも間違いなく好まれる理由です?

私が知る限り、HFT 担当者は入ってくる市場データにできるだけ速く反応する必要がありますが、これは必ずしも厳しいリアルタイム要件ではありません。遅いと不利になるのは確かですが、各応答で特定の速度を保証する必要はありません。高速な平均が必要なだけです。

編集

そうです、これまでのところいくつかの良い答えがありますが、かなり一般的です (よく踏まれた場所)。HFT 関係者が実行するプログラムの種類を指定させてください。

主な基準は応答性です。注文が市場に出たら、最初に反応できるようにしたいと考えています。あなたが遅れた場合、他の誰かがあなたの前にそれを引き継ぐかもしれませんが、各企業はわずかに異なる戦略を持っているので、1 回の繰り返しが少し遅くても大丈夫かもしれません.

プログラムは終日実行され、ユーザーの介入はほとんどありません。新しい市場データを処理する関数は、1 秒間に数十回 (場合によっては数百回) 実行されます。

これらの企業は通常、ハードウェアの価格に制限がありません。

4

15 に答える 15

37

まず、1ミリ秒はHFTの永遠です。そうでない場合は、ドメインについてもう少し読んでおくとよいでしょう。(交換所から100マイル離れているようなものです。)基本的な待ち行列理論の教科書にある公式が示すように、スループットと遅延は深く絡み合っています。同じ式でジッター値が示されます(ネットワークファブリックが正しく、十分なコアを構成していない場合は、CPUキュー遅延の標準偏差が支配的であることがよくあります)。

HFTアービトラージの問題の1つは、スプレッドを取得することを決定すると、利益を実現するために2つ(またはそれ以上)のレッグがあることです。すべての足を打つことができなかった場合、あなたは本当に望まないポジション(そしてその後の損失)を残す可能性があります-結局のところ、あなたは投資せずに裁定取引をしていました。

あなたの戦略が(非常に短期的な!!!)将来を予測していない限り、あなたはポジションを望んでいません(そしてこれは、信じられないかもしれませんが、非常にうまくいきます)。取引所から1ミリ秒離れている場合、注文のかなりの部分が実行されず、必要なものが選択されます。ほとんどの場合、片足を実行したものは敗者になるか、少なくとも利益を生まないでしょう。

あなたの戦略が議論のために何であれ、それが55%/ 45%の勝ち/負けの比率になるとしましょう。勝敗率のわずかな変化でさえ、収益性に大きな変化をもたらす可能性があります。

re:「数十(数百)も実行」は桁違いに見えます20000ティックを見ても、1秒は低いように見えますが、これは彼が見ている機器セットの1日中の平均かもしれません。

任意の秒で見られるレートには大きな変動があります。例を挙げましょう。私のテストのいくつかでは、このストリームの1秒あたりのレートが0 mps(非常にまれ)からピーク秒あたりほぼ2000の相場と取引。(上記の20000が低いと思う理由を参照してください。)

私はこのドメインのインフラストラクチャと測定ソフトウェアを構築しており、私たちが話している数は1秒あたり100000と数百万です。私はC++プロデューサー/コンシューマーインフラストラクチャライブラリを持っており、プロデューサーとコンシューマーの間で1秒あたり約5000000(500万)メッセージをプッシュできます(32ビット、2.4 GHzコア)。これらは、プロデューサー側でnew、construct、enqueue、synchronizeを使用し、同期、デキュー、すべてのバイトにタッチ、仮想デストラクタを実行、無料の64バイトメッセージです。消費者側で。確かに、これは、エンドポイントパイプステージのエンドポイントの場合のように、ソケットIOがない(そしてソケットIOが醜い可能性がある)単純なベンチマークです。これは、空の場合にのみ同期するすべてのカスタム同期クラス、カスタムアロケータ、カスタムロックフリーキューとリスト、ときどきSTL(カスタムアロケータを使用)ですが、多くの場合、カスタム侵入型コレクション(重要なライブラリがあります)です。この分野のベンダーに、ソケットエンドポイントでのバッチ処理を増やすことなく、スループットを4倍(およびそれ以上)にしたことが何度もあります。

私はOrderBookとOrderBook::Universeクラスを持っており、22000を超える楽器の平均で、新規、挿入、検索、部分塗りつぶし、検索、2番目の塗りつぶし、消去、削除シーケンスに2us未満かかります。ベンチマークは、挿入の最初の塗りつぶしと最後の塗りつぶしの間で22000のすべての機器を順番に繰り返すため、安価なキャッシングトリックは必要ありません。同じ本への操作は、22000の異なる本へのアクセスによって分離されています。これらは、実際のデータのキャッシュ特性ではありません。実際のデータは時間的にはるかにローカライズされており、連続した取引は頻繁に同じ本にヒットします。

この作業はすべて、使用されるコレクションのアルゴリズムコストのいずれかで定数とキャッシュ特性を慎重に検討する必要があります。(K O(n)K O(n * log n)などのKが少し見苦しく却下されているように見えることがあります)

私は物事のMarketdataインフラストラクチャ側で働いています。この作業にJavaまたは管理された環境を使用することを考えることさえ考えられません。そして、C ++でこの種のパフォーマンスを得ることができ、管理された環境で100万以上/ mpsのパフォーマンスを得るのは非常に難しいと思う場合)重要な投資銀行やヘッジファンド(250000ドルの給与一流のC++プログラマーは何もありません)C++を使用していません。

管理された環境から2000000+/ mpsのパフォーマンスを実際に得ている人はいますか?私はこの分野の何人かの人々を知っています、そして誰も私にそれについて自慢しませんでした。そして、管理された環境での2mmには、自慢できる権利があると思います。

あるメジャープレーヤーのFIXオーダーデコーダーが12000000フィールドデコード/秒を実行していることを知っています。(3Ghz CPU)それはC ++であり、それを書いた人は、その半分の速度でさえある管理された環境で何かを思い付くようにほとんど誰にでも挑戦しました。

技術的には、楽しいパフォーマンスの課題がたくさんある興味深いエリアです。原資産のセキュリティが変更されたときのオプション市場を考えてみてください。たとえば、有効期限が3つまたは4つの異なる6つの未払いの価格ポイントがある可能性があります。今、各取引について、おそらく10-20の見積もりがありました。これらの見積もりは、オプションの価格変更を引き起こす可能性があります。したがって、取引ごとに、オプションの見積もりに100または200の変更がある可能性があります。これは大量のデータであり、大型ハドロン衝突型加速器のような量のデータではありませんが、それでも少し難しい問題です。キーストロークの処理とは少し異なります。

FPGAについての議論さえ続いています。多くの人々は、3GHZコモディティHWで実行される適切にコーディングされたパーサーが500MHzFPGAを打ち負かすことができるという立場を取っています。ただし、FPGAベースのシステムは少し遅い(そうではないとは言えませんが)場合でも、遅延分布が狭くなる傾向があります。(「傾向」を読んでください-これは包括的なステートメントではありません)もちろん、Cfrontを介してプッシュし、FPGAイメージジェネレーターを介してプッシュする優れたC ++パーサーがある場合は、別の議論があります...

于 2010-07-06T05:05:41.140 に答える
28

その多くは、事実と理論の単純な違いに帰着します。人々は、なぜ Java が C++ よりも高速である必要がある (または少なくとも高速である可能性がある) かを説明する高度な理論を持っています。ほとんどの引数は、Java または C++自体とはほとんど関係がありませんが、動的コンパイルと静的コンパイルとの関係はほとんどありません。Java と C++ は実際には 2 つの例にすぎません (もちろん、Java を静的にコンパイルすることも、C++ をコンパイルすることも可能です)。動的に)。これらの人々のほとんどは、自分の主張を「証明」するためのベンチマークを持っています。これらのベンチマークを詳細に調べると、かなりの数の場合、必要な結果を得るためにかなり極端な手段を講じていることがすぐに明らかになります (たとえば、かなりの数が Java のコンパイル時に最適化を有効にしますが、具体的にはC++ のコンパイル時に最適化を無効にしました)。

これをComputer Language Benchmarks Gameと比較すると、ほとんど誰でもエントリを送信できるため、すべてのコードが合理的な程度 (場合によっては不合理な程度) に最適化される傾向があります。かなりの数の人々がこれを本質的に競争と見なしており、各言語の擁護者が自分の好みの言語が最適であることを「証明」するために最善を尽くしていることは明らかです。誰でも問題の実装を提出できるため、特に不十分な提出は全体的な結果にほとんど影響しません。この状況では、C と C++ が明確なリーダーとして浮上します。

さらに悪いことに、これらの結果は、完全に正確であるよりも、 Java の方が優れていることを示している可能性があります。特に、C または C++ を使用していて、パフォーマンスを重視する人は、g++ の代わりに Intel のコンパイラを使用できます (多くの場合、使用する予定です)。これにより、通常、g++ と比較して速度が少なくとも 20% 向上します。

編集(jalfによって提起されたいくつかのポイントに応じて、コメントに合理的に収まるには長すぎます):

  1. ポインターはオプティマイザーのライターにとって悪夢です。これは実際には(かなり)誇張されています。ポインターはエイリアシングの可能性につながり、特定の状況下で特定の最適化を妨げます。とはいえ、インライン化は多くの場合、悪影響を防ぎます (つまり、コンパイラは、エイリアシングが存在する可能性があるという仮定の下で常にコードを生成するのではなく、エイリアシングがあるかどうかを検出できます)。コードがエイリアシングを想定しなければならない場合でも、キャッシングを行うことでパフォーマンスへの影響が最小限に抑えられます (つまり、L1 キャッシュ内のデータは、レジスタ内のデータよりわずかに遅いだけです) エイリアシングを防止すると、C++ でのパフォーマンスは向上しますが、思ったほどではありません。

  2. ガベージコレクターを使用すると、割り当てがはるかに高速になります。多くの C++ 実装のデフォルトアロケータが、ほとんどの (現在の) ガベージ コレクション アロケータが提供するものより遅いことは確かです。これは、C++ では割り当てがスタック上にある傾向があり、これも高速であるという事実によって (少なくともある程度) バランスが取れていますが、GC 言語では通常、ほとんどすべての割り当てがヒープ上にあります。さらに悪いことに、マネージ言語では通常、各オブジェクトに個別にスペースを割り当てますが、C++ では通常、スコープ内のすべてのオブジェクトに一緒にスペースを割り当てます。

また、C++ がグローバルおよびクラスごとの両方でアロケーターの置き換えを直接サポートしていることも事実であるため、割り当て速度が本当に問題になる場合は、通常はかなり簡単に修正できます。

最終的に、jalf は正しいです。これらの点はどちらも、間違いなく管理された」実装を支持します。ただし、その改善の程度は視野に入れておく必要があります。動的にコンパイルされた実装を多くのコードで高速に実行するには十分ではありません。最初からそれらを可能な限り優先するように設計されたベンチマークでさえありません。

Edit2: Jon Harrop が 2 (10 億分の 1) セントの価値を挿入しようとしたようです。彼を知らない人のために説明すると、Jon は何年もの間悪名高い 荒らし スパマー あり、雑草をまく新しい地盤を探しているようです。私は彼のコメントに詳細に返信しようとしますが、(彼にとって典型的なことですが) それは、意味のある返信が不可能なほど実際の内容をほとんど含まない、修飾されていない、サポートされていない一般化のみで構成されています. できることは、見物人に、彼が不誠実で利己的で、無視するのが最善であることで有名になったことを公正に警告することだけです.

于 2010-07-04T15:41:03.337 に答える
14

JIT コンパイラーは理論的には多くの最適化を実行できますが、どのくらい待つつもりですか? C++ アプリは、コンパイルがオフラインで行われ、ユーザーがそこに座って指をタップして待っているわけではないため、コンパイルに何時間もかかることがあります。

JIT コンパイラーは数ミリ秒以内に終了する必要があります。では、最も複雑な最適化を回避できるのはどれだと思いますか?

ガベージコレクターも要因です。手動のメモリ管理自体よりも遅いからではありませんが (償却コストはかなり高く、手動のメモリ処理に匹敵すると思います)、予測しにくいからです。これ、ほとんどすべての時点で失速を引き起こす可能性があり、非常に応答性が要求されるシステムでは受け入れられない可能性があります。

そしてもちろん、言語はさまざまな最適化に役立ちます。C++ を使用すると、実質的にメモリ オーバーヘッドがなく、多くの高レベル操作 (クラス構築など) が基本的に無料で、非常にタイトなコードを記述できます。

一方、C# では、大量のメモリを浪費します。Objectまた、実際のクラスが空であっても、ベースを初期化する必要があるため、単純にクラスをインスタンス化すると、かなりのオーバーヘッドが発生します。

C++ では、コンパイラは未使用のコードを積極的に取り除くことができます。C# では、リフレクションで見つけられるように、そのほとんどがそこにある必要があります。

一方、C# にはポインターがありません。これは、最適化コンパイラーの悪夢です。また、マネージ言語でのメモリ割り当ては、C++ よりもはるかに安価です。

どちらの方法にも利点があるため、単純な「どちらか一方」の答えが得られると期待するのは単純です。正確なソースコード、コンパイラ、OS、実行されているハードウェアに応じて、どちらかが高速になる場合があります。また、ニーズによっては、生のパフォーマンスが最大の目標ではない場合があります。おそらく、予期しない失速を回避するために、応答性にもっと関心があるでしょう。

一般に、典型的な C++ コードは同等の C# コードと同様に動作します。速い時もあれば遅い時もありますが、おそらく劇的な違いはありません。

しかし、繰り返しになりますが、正確な状況によって異なります。また、最適化にどれだけの時間を費やすかにもよります。できるだけ多くの時間を費やしても構わないと思っているのであれば、通常、C++ コードは C# よりも優れたパフォーマンスを達成できます。手間がかかるだけです。

もちろん、もう 1 つの理由は、C++ を使用しているほとんどの企業が、特に捨てたくない大規模な C++ コード ベースを既に持っていることです。(一部の) 新しいコンポーネントをマネージ言語に徐々に移行したとしても、機能し続けるためにはそれが必要です。

于 2010-07-04T15:13:56.107 に答える
9

これらの企業は通常、ハードウェアの価格に制限がありません。

彼らがソフトウェアの高価さを気にしないのであれば、もちろん C++ の方が高速であると思います。および/またはカーネル内でコードを実行し (リング遷移を回避)、リアルタイム O/S でコードを実行したり、ネットワーク プロトコル スタックに密接に結合したりできます。

于 2010-07-04T15:48:19.547 に答える
2

単純な事実として、C++ は速度を重視して設計されています。C#/Java は違います。

ジェネリックである std::sort または std::for_each のゼロ オーバーヘッドと比較して、これらの言語 (IEnumerable など) に固有の無数の継承階層を取り上げます。C++ の生の実行速度は必ずしも速くはありませんが、プログラマーは高速またはオーバーヘッドのないシステムを設計できます。バッファ オーバーランのようなものでさえ、検出をオフにすることはできません。C++ では、制御できます。基本的に、C++ は高速な言語です。使用しないものにお金はかかりません。対照的に、C# では、たとえば stackalloc を使用すると、バッファー オーバーラン チェックを行うことはできません。スタック上または連続してクラスを割り当てることはできません。

また、コンパイル時間の問題もあります。C++ アプリでは、コンパイルと開発の両方に時間がかかる場合があります。

于 2010-07-04T15:57:40.493 に答える
2

パフォーマンス以外にも C++ を使用する理由があります。C および C++ コードの膨大な既存のライブラリがあります。そのすべてを別の言語で書き直すのは現実的ではありません。P/Invoke などを正しく機能させるには、ターゲット コードを別の場所から呼び出せるように設計する必要があります。C++ クラスに対して P/Invoke を実行できないため、完全に C API を公開するものの周りに何らかのラッパーを作成する必要があります。

最後に、P/Invoke は非常にコストのかかる操作です。

JIT コンパイラーはどんどん良くなっています。プログラムの実行中に最適化を行うことができます

はい、彼らはこれを行うことができます。しかし、どの C++ コンパイラでも同じ最適化を実行できることを忘れています。確かに、コンパイル時間は悪化しますが、そのような最適化を実行時に行わなければならないという事実自体がオーバーヘッドです。マネージ言語が特定のタスクで C++ よりも優れている場合がありますが、これは通常、ランタイムの最適化の結果ではなく、メモリ モデルが原因です。厳密に言えば、もちろん C++、EDIT: C# の文字列の処理、/EDIT などでそのようなメモリ モデルを使用できますが、JIT 担当者ほどコードの最適化に多くの時間を費やす C++ プログラマはほとんどいません。

マネージ言語に継承されるいくつかのパフォーマンスの問題、つまりディスク I/O があります。これは 1 回限りのコストですが、アプリケーションによってはかなりの額になる可能性があります。最高のオプティマイザーを使用しても、プログラムの開始時にディスクから 30MB 以上の JIT コンパイラーをロードする必要があります。一方、C++ バイナリがそのサイズに近づくことはめったにありません。

于 2010-07-04T15:11:14.990 に答える
2

私たちのコードのほとんどは、数千台のマシンのグリッド上で実行する必要があります。

この環境が議論を変えると思います。たとえば、c++ と c# の実行速度の差が 25% の場合、他の要因が影響します。これがグリッド上で実行される場合、プロセス全体がマシン全体に分散されると、問題が発生したり、さらにいくつかのマシンを割り当てたり購入したりすることで解決されたりしないため、コーディング方法に違いはありません。最も重要な問題とコストは「市場投入までの時間」になる可能性があり、c# が勝者でより高速なオプションであることが証明される可能性があります。

c++ と c# のどちらが速いですか?

C#で半年……

于 2010-07-06T13:29:43.070 に答える
2

これはちょっと話題から外れているかもしれませんが、私は数週間前にあなたが興味を持っているように見えるビデオを見ました: http://ocaml.janestreet.com/?q=node/61

これは、取引の主要言語として ocaml を使用することを決定した商社からのものであり、彼らの動機はあなたに啓発的であると思います (基本的に、彼らは速度はもちろんですが、強力なタイピングと迅速なインクリメントのための機能的なスタイルだけでなく、分かりやすくなります)。

于 2010-07-04T19:48:49.517 に答える
1

C ++で最も興味深いことの1つは、パフォーマンスの数値は良くないが、 信頼性が高いことです。

Java / C#/ ...よりも必ずしも高速ではありませんが、実行全体で一貫しています

ネットワークの場合と同様に、スループットは安定した遅延ほど重要ではない場合があります

于 2010-07-06T13:58:22.347 に答える
1

プログラミング言語だけの問題ではなく、ハードウェアとオペレーティング システムが関連します。
リアルタイム オペレーティング システム、リアルタイム プログラミング言語、および効率的な (!) プログラミングで得られる最高の全体的なパフォーマンス。

したがって、オペレーティング システムの選択にはかなりの可能性があり、言語の選択にもいくつかの可能性があります。C、Realtime Java、Realtime Fortran などがあります。

または、オペレーティング システムのコストを削減するために FPGA/プロセッサをプログラミングすることで、最良の結果が得られるかもしれません。

あなたがしなければならない最大の選択は、開発を容易にし、より安定して動作する言語を選択することを支持して、いくつの可能なパフォーマンス最適化を無視するかです。なぜなら、バグを減らすことができ、システムの可用性が高くなるからです。これは見逃すべきではありません。見つけにくい小さなバグが原因で数ポイントごとにクラッシュする他のどのアプリケーションよりも 5% 高速に動作するアプリケーションを開発しても、成功はありません。

于 2010-07-04T15:59:07.773 に答える
1

HFT では、レイテンシはスループットよりも大きな問題です。データ ソースに固有の並列性があれば、いつでもより多くのコアを問題に投入できますが、より多くのハードウェアで応答時間を補うことはできません。言語が事前にコンパイルされている場合でも、ジャス​​トインタイムでコンパイルされている場合でも、ガベージ コレクションによってレイテンシが破壊される可能性があります。ガベージ コレクションのレイテンシが保証されたリアルタイム JVM が存在します。これはかなり新しいテクノロジであり、調整が難しく、途方もなく費用がかかりますが、リソースがあれば実行できます。初期の採用者が現在進行中の研究開発に資金を提供しているため、おそらく今後数年間ではるかに主流になるでしょう.

于 2010-07-04T16:02:42.373 に答える
0

Nikie は次のように書いています。「.NET スレッドではなく、C++ スレッドでできることを説明していただけますか?」</p>

.Net を使用したスレッド化は、C++ のスレッド化ができる事実上すべてを実行できますが、次の点を除きます。

  1. COM でカプセル化されたバイナリ コードの効率的な実行。たとえば、アプリケーション開発者には秘密にしておく必要がある機密性の高いアルゴリズムです。(HFTに関連する可能性があります)
  2. 分厚いビルディング ブロック (ラップされた OS API と同期およびシグナリング OS プリミティブ) を使用して、システム リソースを使い果たすことのない無駄のないスレッドを作成します。(HFT でのパフォーマンスの時間最適化のための並列アルゴリズムに非常に関連しています)
  3. ビジネス プロセス アプリケーションのスループットを、同じハードウェアで同じ待機時間で 10 回以上スケールアップする。(HFT では関係ありません)
  4. ハードウェア単位で同時に処理されるユーザー操作の数を 100 倍以上にスケールアップします。(HFT では関係ありません)

より多くの CPU コアを使用しても、.Net のビルディング ブロックによるシステム リソースの枯渇を完全に補償することはできません。

于 2010-07-07T05:17:11.940 に答える
0

仮想実行エンジン (JVM または .Net の CLR) では、プロセス インスタンスを必要な数のスレッドで実行できないため、時間効率の良い方法で作業を構造化することはできません。

対照的に、プレーンな C++ では、並列アルゴリズムの実行と、タイム クリティカルな実行パス外でのオブジェクトの構築が可能になります。シンプルでエレガントです。さらに、C++ では使用した分だけ料金が発生します。

于 2010-07-05T13:05:58.060 に答える
0

この場合、すでに述べたこと以外に c++ (または下位レベル) を好む大きな理由は、下位レベルであることの適応性の利点がいくつかあることです

ハードウェア技術が変化した場合は、いつでも__asm { }ブロックにドロップして、言語/コンパイラが追いつく前に実際に使用できます

たとえば、Java ではまだSIMD がサポートされていません。

于 2010-07-04T18:59:24.473 に答える
0

ここでの象は、C++ が Java よりも高速であるという事実です

私たちは皆それを知っています。しかし、私が今行ったように、率直に述べた場合、この議論の余地のないトピックについて有意義な議論に参加するふりをすることはできないこともわかっています. あなたのアプリケーションでは、C++ は Java よりどれくらい速いですか? それは議論の余地のある話題の輪を持っていますが、残念ながら、アプリケーションを両方の言語で実装しない限り、それは常に仮説に過ぎず、その時点で議論の余地はありません.

最初の設計会議に戻りましょう。プロジェクトの厳しい要件は高性能です。部屋にいる誰もが「C++」と他のいくつかのコンパイル済み言語を考えるでしょう。Java や C# を提案する部屋にいる人は、証拠 (つまり、プロトタイプ) でそれを正当化する必要があります。仮説ではなく、ベンダーの主張でもなく、プログラマーのゴシップ サイトでの声明でもなく、「こんにちは」などではありません。世界」のベンチマーク。

現状では、仮説的に可能なことではなく、 知っていることで前進する必要があります。

于 2010-07-06T14:09:45.547 に答える