15

私がここで取り組んでいるシステムは、.net 2.0 より前に作成されたものであり、ジェネリックの利点がありませんでした。最終的に 2.0 に更新されましたが、時間の制約によりコードのリファクタリングは行われませんでした。オブジェクトとして物を格納する ArraysLists などをコードが使用する場所がいくつかあります。

パフォーマンスの観点から、ジェネリックを使用するためにコードを変更することはどの程度重要ですか? ボックス化とボックス化解除などのパフォーマンスの観点からは非効率的ですが、変更することで実際にパフォーマンスがどの程度向上するのでしょうか? ジェネリックは将来的に使用するものですか、それとも良心の努力を払って古いコードを更新する必要があるほど十分なパフォーマンスの変化がありますか?

4

12 に答える 12

14

技術的には、ジェネリックのパフォーマンスは、おっしゃる通りより優れています。ただし、パフォーマンスが非常に重要であり、他の領域で既に最適化されている場合を除き、別の場所に時間を費やすことで、はるかに優れた改善が得られる可能性があります.

私は提案します:

  • 今後はジェネリックを使用してください。
  • しっかりした単体テストがある場合は、コードに触れるときにジェネリックにリファクタリングします
  • あちこちで数ミリ秒ではなく、パフォーマンスを大幅に向上させるリファクタリング/測定 (データベース呼び出し、データ構造の変更など) に他の時間を費やします。

もちろん、パフォーマンス以外にもジェネリックに変更する理由があります。

  • コンパイル時に型をチェックするため、エラーが発生しにくい
  • より読みやすく、あちこちにキャストする必要がなく、コレクションに格納されている型が明らかです
  • 今後ジェネリックを使用している場合は、どこでもジェネリックを使用する方がクリーンです
于 2008-09-18T17:56:42.803 に答える
8

これは、100KBのファイルからの文字列を100,000回単純に解析して得られた結果です。Generic List(Of char)は、ファイルを100,000回通過するのに612.293秒かかりました。ArrayListは、ファイルを100,000回通過するのに2,880.415秒かかりました。これは、このシナリオでは(マイレージ異なるため)ジェネリックリスト(文字の)が4.7倍高速であることを意味します。

これが私が100,000回実行したコードです:

Public Sub Run(ByVal strToProcess As String) Implements IPerfStub.Run
    Dim genList As New ArrayList

    For Each ch As Char In strToProcess.ToCharArray
        genList.Add(ch)
    Next

    Dim dummy As New System.Text.StringBuilder()
    For i As Integer = 0 To genList.Count - 1
        dummy.Append(genList(i))
    Next

End Sub

 Public Sub Run(ByVal strToProcess As String) Implements IPerfStub.Run
     Dim genList As New List(Of Char)

     For Each ch As Char In strToProcess.ToCharArray
         genList.Add(ch)
     Next

     Dim dummy As New System.Text.StringBuilder()
     For i As Integer = 0 To genList.Count - 1
         dummy.Append(genList(i))
     Next
 End Sub
于 2008-09-18T19:02:20.867 に答える
4

確実に知る唯一の方法は、dotTrace などのツールを使用してコードをプロファイリングすることです。

http://www.jetbrains.com/profiler/

特定のアプリケーションではボックス化/ボックス化解除が簡単であり、リファクタリングする価値がない可能性があります。今後も、コンパイル時のタイプ セーフのため、ジェネリックの使用を検討する必要があります。

于 2008-09-18T17:51:07.043 に答える
3

ジェネリックは、Java であれ .NET であれ、パフォーマンスのためではなく、設計とタイプ セーフのために使用する必要があります。オートボクシングはジェネリック (本質的に暗黙的なオブジェクトからプリミティブへの変換) とは異なります。また、前述のように、反復によるパフォーマンスの低下を引き起こす算術演算やその他の操作が多数ある場合は、プリミティブの代わりにそれらを使用しないでください。暗黙的なオブジェクトの作成/破棄。

全体として、パフォーマンスではなく、型の安全性/設計の目的でクリーンアップする必要がある場合にのみ、既存のコードを更新して、今後使用することをお勧めします。

于 2008-09-18T17:54:36.083 に答える
1

それは場合によって異なりますが、最善の答えは、コードをプロファイルして確認することです。私は AQTime が好きですが、これ用のパッケージがいくつかあります。

一般に、ArrayList が頻繁に使用されている場合は、汎用バージョンに切り替える価値があります。実際には、パフォーマンスの違いを測定することさえできない可能性が最も高いです。ボックス化とボックス化解除は追加の手順ですが、最新のコンピューターは非常に高速であるため、ほとんど違いはありません。ArrayList は実際には適切なラッパーを備えた単なる通常の配列であるため、ジェネリックへの変換よりも優れたデータ構造の選択 (ArrayList.Remove は O(n)!) により、より多くのパフォーマンスが得られることがわかるでしょう。

編集: Outlaw Programmer には良い点があります。ジェネリックを使用してボックス化およびボックス化解除を行うことになりますが、それは暗黙のうちに行われます。ただし、キャストと「is/as」キーワードからの例外とnullのチェックに関するすべてのコードは少し役立ちます。

于 2008-09-18T17:53:54.713 に答える
0

ジェネリックは、パフォーマンスが大幅に向上する値型 (int、bool、struct など) を使用する場合は特に、パフォーマンスが大幅に向上します。

  1. 値型で Arraylist を使用すると、ボックス化/ボックス化解除が発生します。これを数百回実行すると、一般的な List を使用するよりも大幅に遅くなります。

  2. 値型をオブジェクトとして格納する場合、アイテムごとに最大 4 つの時間メモリが必要になります。この量は RAM を使い果たすことはありませんが、キャッシュ メモリが小さいほど含まれるアイテムが少なくなる可能性があります。つまり、長いコレクションを繰り返し処理している間に、メイン メモリからキャッシュに多数のコピーが作成され、アプリケーションの速度が低下します。

ここについて書きました。

于 2008-09-20T07:30:07.463 に答える
0

ジェネリックを使用すると、後のバージョンの c# で linq などを活用したい場合に、コードがより単純で使いやすくなります。

于 2009-01-22T04:37:19.947 に答える
0

最大の利点は、メンテナンス フェーズにあります。ジェネリックは、変換やキャストの問題に対処する必要がなく、処理と更新がはるかに簡単です。これが頻繁にアクセスするコードである場合は、必ず努力してください。これが何年も触れられていないコードであれば、私は気にしません。

于 2008-09-18T17:52:44.997 に答える
0

オートボクシング/アンボクシングはジェネリックと何の関係がありますか? これは単なる型安全性の問題です。非ジェネリック コレクションでは、オブジェクトの実際の型に明示的にキャスト バックする必要があります。ジェネリックでは、この手順を省略できます。どちらの方法でもパフォーマンスの違いはないと思います。

于 2008-09-18T17:54:02.043 に答える
0

私の古い会社は実際にこの問題を考えていました。私たちが取ったアプローチは、リファクタリングが簡単な場合はそれを行います。そうでない場合 (つまり、あまりにも多くのクラスに触れることになります)、しばらく放置してください。それを行う時間があるかどうか、またはコーディングするより重要な項目 (つまり、クライアントに実装する必要がある機能) があるかどうかに大きく依存します。

繰り返しになりますが、クライアント向けの作業を行っていない場合は、リファクタリングに時間を費やしてください。これにより、コードの可読性が向上します。

于 2008-09-18T17:54:34.977 に答える
0

コードにどれだけあるかによって異なります。UI で大きなリストをバインドまたは表示すると、パフォーマンスが大幅に向上する可能性があります。

ArrayList があちらこちらに散らばっているだけの場合、それをクリーンアップするだけで大​​した問題にはならないでしょうが、全体的なパフォーマンスに大きな影響を与えることもありません。

コード全体で多くの ArrayLists を使用していて、それらを置き換えるのが大変な場合 (スケジュールに影響を与える可能性があるもの)、if-you-touch-it-change-it アプローチを採用できます。

ただし、主なことは、Generics の方がはるかに読みやすく、強力な型付けによってアプリ全体でより安定しているということです。パフォーマンスだけでなく、コードの保守性と安定性も向上します。すぐにできるなら、そうするといいです。

プロダクト オーナーから賛同を得られる場合は、クリーンアップすることをお勧めします。後でコードがもっと好きになります。

于 2008-09-18T17:57:57.557 に答える
0

ArrayLists 内のエンティティが Object 型の場合、それらを正しい型にキャストしないことで少しは利益が得られます。それらが値型 (構造体または Int32 のようなプリミティブ) である場合、ボックス化/ボックス化解除プロセスにより多くのオーバーヘッドが追加され、ジェネリック コレクションははるかに高速になります。

これは、件名に関するMSDNの記事です

于 2008-09-18T17:59:34.027 に答える