web-dev-qa-db-ja.com

C#ジェネリックにはパフォーマンス上の利点がありますか?

私は、様々なエンティティを表すデータクラスの数を持っています。

ジェネリックとインターフェイスを使用してジェネリッククラスを作成する(たとえば、XMLを印刷または出力する)か、各データクラスを処理するために個別のクラスを作成するか。

パフォーマンス上の利点またはその他の利点(個別のクラスを作成する時間を節約する以外)はありますか?

37
Roberto Bonini

ジェネリックスを使用することには、パフォーマンス上の大きなメリットがあります ボックス化とボックス化解除 を廃止します。独自のクラスを開発する場合と比較すると、コイントスです(コインの片側がもう一方よりも重くなります)。フレームワークの作成者をしのぐことができると思う場合にのみ、自分でロールしてください。

59
Danimal

はいだけでなく、HECKYES。彼らがどれほど大きな違いを生むことができるか私は信じていませんでした。 ArrayListsとHashTablesを使用するコアコードのごく一部をジェネリックスに書き直した後、VistaDBでテストを行いました。 250%以上は速度の向上でした。

テストについての私のブログを読んでください ジェネリックと弱いタイプのコレクションで行いました。その結果は私たちの心を吹き飛ばしました。

弱い型のコレクションを使用していた多くの古いコードを強い型のコレクションに書き直し始めました。 ADO.NETインターフェイスに関する私の最大の不満の1つは、データを出し入れするためのより強く型付けされた方法を公開していないことです。オブジェクトからのキャスト時間とその逆のキャスト時間は、大量のアプリケーションでは絶対的なキラーです。

強い型付けのもう1つの副作用は、コード内で弱い型付けの参照の問題が頻繁に発生することです。 構造体の実装 を介して、GCに圧力をかけないようにすることで、コードをさらに高速化できることがわかりました。これを強く入力することと組み合わせると、最高の速度向上が得られます。

ドットネットランタイム内で弱い型のインターフェイスを使用しなければならない場合があります。可能な限り、強くタイプされたままにする方法を探してください。それは、重要なアプリケーションのパフォーマンスに大きな違いをもたらします。

20
Jason Short

C#のジェネリックは、CLRの観点からは真のジェネリック型です。ジェネリッククラスとまったく同じことを行う特定のクラスのパフォーマンスに根本的な違いがあってはなりません。これは、Java Genericsとは異なります。ジェネリックスは、必要に応じて自動化された型キャストや、コンパイル時に拡張されるC++テンプレートです。

これは、基本的な設計を説明する、やや古い良い論文です: "。NET共通言語ランタイムのジェネリックの設計と実装"

特定のタスクのクラスを手書きする場合は、ジェネリック型のインターフェースを介して追加の迂回が必要になるいくつかの側面を最適化できます。

要約すると、パフォーマンス上の利点があるかもしれませんが、最初に一般的なソリューションをお勧めし、次に必要に応じて最適化します。これは、多くの異なるタイプでジェネリックをインスタンス化することを期待している場合に特に当てはまります。

15
Andrew Queisser

別の質問に対して、ArrayListとGeneric Listの簡単なベンチマークを行いました: Generics vs. Array Lists 、マイレージは異なりますが、GenericListはArrayListより4.7倍高速でした。

そうです、ボクシング/ボックス化解除は重要ですif多くの操作を行っている場合。単純なCRUDを実行している場合は、心配する必要はありません。

7
torial

ジェネリックスは、コードをパラメーター化し、繰り返しを回避する方法の1つです。プログラムの説明と、すべてのデータオブジェクトを処理するための個別のクラスを作成するという考えを見ると、ジェネリックに傾倒します。同じことを行う多くのクラスではなく、単一のクラスで多くのデータオブジェクトを処理することで、パフォーマンスが向上します。そしてもちろん、コードを変更する能力で測定されるパフォーマンスは、通常、コンピューターのパフォーマンスよりも重要です。 :-)

6
Hristo Deshev

Microsoftによると、ジェネリックスはキャスト(ボックス化/ボックス化解除プリミティブ)よりも高速ですこれは本当です。彼らはまた、ジェネリックスが参照型間でキャストするよりも優れたパフォーマンスを提供すると主張していますこれは真実ではないようです(誰もそれを完全に証明することはできません)。

Tony Northrup-MCTS 70-536:Application Development Foundationの共著者-は、同じ本の中で次のように述べています。

ジェネリックのパフォーマンス上の利点を再現できませんでした。ただし、Microsoftによると、ジェネリックはキャストを使用するよりも高速です。実際には、キャストはジェネリックを使用するよりも数倍高速であることが証明されました。ただし、アプリケーションのパフォーマンスの違いに気付かない可能性があります。 (100,000回以上の反復での私のテストは数秒しかかかりませんでした。)したがって、ジェネリックはタイプセーフであるため、引き続き使用する必要があります。

参照型間のキャストと比較して、ジェネリックでこのようなパフォーマンスの利点を再現することはできませんでした。したがって、パフォーマンスの向上は「重要」というよりも「想定」されていると言えます。

4
JohnIdol

たとえば、一般的なリストを使用するタイプの特定のリストと比較すると、違いは最小限に抑えられ、JITコンパイラの結果はほぼ同じになります。

ジェネリックリストをオブジェクトのリストと比較すると、ジェネリックリストには大きな利点があります。値型のボックス化/ボックス化解除や参照型の型チェックがありません。

また、.netライブラリのジェネリックコレクションクラスは大幅に最適化されており、自分でうまくやる可能性はほとんどありません。

3
Nir

ジェネリックはより速いです!

また、トニー・ノースラップが彼の本にジェネリックと非ジェネリックのパフォーマンスについて間違ったことを書いていることも発見しました。

私はこれについてブログに書いています: http://andriybuday.blogspot.com/2010/01/generics-performance-vs-non-generics.html

これは、著者がジェネリックと非ジェネリックのパフォーマンスを比較する素晴らしい記事です。

nayyeri.net/use-generics-to-improve-performance

3
Andriy Buday

MSDNのRicoMarianiのブログも参照してください。

http://blogs.msdn.com/ricom/archive/2005/08/26/456879.aspx

Q1:どちらが速いですか?

Genericsバージョンはかなり高速です。以下を参照してください。

記事は少し古いですが、詳細を説明しています。

2
John Gardner

あるインターフェースのメソッドを呼び出してその作業を行うジェネリッククラスを考えている場合、インターフェースメソッドの呼び出しは(非仮想)関数呼び出しよりも遅いため、既知の型を使用する特定のクラスよりも遅くなります。

もちろん、コードがパフォーマンスが重要なプロセスの遅い部分でない限り、明確さを重視する必要があります。

2
Khoth

ジェネリックコレクションとボクシングなどの場合、ArrayListのような古いコレクションでは、ジェネリックがパフォーマンスを向上させます。しかし、ほとんどの場合、これはジェネリック医薬品の最も重要な利点ではありません。はるかに大きなメリットがあるのは2つあると思います。

  1. 型安全性。
  2. 自己文書化、別名より読みやすい。

ジェネリックは型安全性を促進し、より均質な収集を強制します。 intを期待しているときに、文字列に遭遇したと想像してみてください。痛い。

ジェネリックコレクションは、より自己文書化されています。以下の2つのコレクションについて考えてみます。

ArrayList listOfNames = new ArrayList();
List<NameType> listOfNames = new List<NameType>();

最初の行を読むと、listOfNamesは文字列のリストだと思うかもしれません。違う!実際には、NameTypeタイプのオブジェクトを格納しています。 2番目の例では、タイプがNameType(または子孫)である必要があるだけでなく、コードがより読みやすくなっています。 TypeNameを見つけて、コードを見るだけでその使用方法を学ぶ必要があることをすぐに知っています。

StackOverflowでこれらの「xはyよりもパフォーマンスが良いか」という質問をたくさん見ました。ここでの質問は非常に公平でした、そしてそれが判明したように、ジェネリックはあなたが猫の皮を剥ぐ方法で勝利です。しかし、結局のところ、ポイントはユーザーに何か便利なものを提供することです。確かに、アプリケーションは実行できる必要がありますが、クラッシュしないようにする必要があり、バグや機能の要求に迅速に対応できる必要があります。これらの最後の2つのポイントが、ジェネリックコレクションの型安全性とコードの可読性とどのように関連しているかがわかると思います。逆の場合、ArrayListがList <>を上回っていれば、パフォーマンスの違いが大きくない限り、List <>の実装を採用するでしょう。

パフォーマンスに関する限り(一般的に)、キャリアの過程で、これらの領域でパフォーマンスのボトルネックの大部分が見つかることは間違いありません。

  1. データベースまたはデータベースクエリ(インデックス作成などを含む)の設計が不十分、
  2. 不十分なメモリ管理(disposeの呼び出しを忘れる、スタックが深い、オブジェクトを長く保持しすぎるなど)、
  3. 不適切なスレッド管理(スレッドが多すぎる、デスクトップアプリのバックグラウンドスレッドでIO)を呼び出さないなど)、
  4. 悪いIOデザイン。

これらはいずれも、単一行ソリューションでは修正されていません。私たちプログラマー、エンジニア、オタクは、パフォーマンスに関するちょっとしたコツをすべて知りたいと思っています。しかし、私たちがボールに目を離さないことが重要です。上記の4つの領域で優れた設計とプログラミングの実践に焦点を当てることで、パフォーマンスのわずかな向上を心配する以上のことがさらに促進されると思います。

2
Jason Jackson

ボクシングを廃止できるだけでなく、基礎となる実装が変更されたため、ジェネリック実装は、参照型を持つ非ジェネリック実装よりもいくらか高速です。

オリジナルは、特定の拡張モデルを念頭に置いて設計されました。このモデルは実際には使用されませんでした(とにかく悪い考えでした)が、設計上の決定により、いくつかのメソッドが仮想化され、インライン化できなくなりました(この点に関する現在および過去のJIT最適化に基づく)。

この決定は新しいクラスで修正されましたが、バイナリを壊す可能性のある変更がなければ、古いクラスで変更することはできません。

さらに、ArrayListの列挙子がヒープ割り当てを必要とするため、(IList <>ではなく)List <>でのforeachによる反復が高速になります。確かに、これは あいまいなバグ につながりました

0
ShuggyCoUk