4

アプリをリファクタリングして高速化しています。そのためのヒントを探していたところ、次のステートメントを見つけました。

「ForEach は For ループ内のコードを単純化できますが、重いオブジェクトであり、For を使用して記述されたループよりも低速です。」

本当?それが書かれたときに真実だった場合、それは今日でも真実ですか、それともパフォーマンスを改善するために foreach 自体がリファクタリングされていますか?

同じソースからのこのヒントについて同じ質問があります。

「可能な場合は、コレクションの代わりに配列を使用してください。配列は通常、特に値型の場合により効率的です。また、可能な場合はコレクションを必要なサイズに初期化してください。」

アップデート

データベース操作に数秒かかっていたため、パフォーマンスのヒントを探していました。

「using」ステートメントは時間の浪費であることがわかりました。

for ループと "using" を逆にすることで、パフォーマンスの問題を完全に解決しました (もちろん、これを機能させるにはリファクタリングが必要でした)。

糖蜜よりも遅いコードは次のとおりです。

for (int i = 1; i <= googlePlex; i++) {
    . . .
    using (OracleCommand ocmd = new OracleCommand(insert, oc)) {
    . . .
    InsertRecord();
    . . .

弾丸よりも高速なコードは次のとおりです。

using (OracleCommand ocmd = new OracleCommand(insert, oc)) {
    for (int i = 1; i <= googlePlex; i++) {
        . . .
        InsertRecord();
        . . .
4

4 に答える 4

9

簡潔な答え:

読みにくいコードは、最終的にソフトウェアの動作とパフォーマンスを低下させます。

長い答え:

初期の .NET には、マイクロ最適化の提案の文化がありました。部分的には、いくつかの Microsoft の内部ツール (FxCop など) が一般の人々の間で人気を得たことが原因でした。その理由の 1 つは、C# がアセンブリ、C、および C++ の後継になりたいという願望があり、パフォーマンス クリティカルなアプリケーションのいくつかの最もホットなコード パスで生のハードウェア パフォーマンスに妨げられずにアクセスできることです。もちろん、これには通常のアプリケーションよりも多くの知識と規律が必要です。フレームワーク コードとアプリ コードにおけるパフォーマンス関連の決定の結果も、まったく異なります。

もちろん、これが C# のコーディング文化に与える最終的な影響はプラスです。しかし、必要に応じて最近のジッターを完全に最適化できるいくつかの CIL 命令を保存するために、foreachorisまたはの使用を停止するのはばかげています。""

アプリにはおそらく非常に多くのループがあり、現在のパフォーマンスのボトルネックはせいぜいそのうちの 1 つかもしれません。読みやすさを犠牲にしてパフォーマンスのボトルネックを「最適化」することは、非常に悪いことです。

于 2012-05-21T16:47:40.753 に答える
6

多くの場合foreach、同等のものよりも遅いのは事実forです。それもまた事実

for (int i = 0; i < myCollection.Length; i++) // Compiler must re-evaluate getter because value may have changed

より遅い

int max = myCollection.Length;
for (int i = 0; i < max; i++) 

しかし、それはおそらくまったく問題にならないでしょう。非常に詳細な説明については、「C# の制御構造 'for' と 'foreach' のパフォーマンスの違い」を参照してください。

アプリケーションのホット スポットを特定するためにプロファイリングを行いましたか? ループ管理のオーバーヘッドに注意を向ける必要があるとしたら、私は驚きます。

于 2012-05-21T16:42:45.557 に答える
4

Red Gate ANTS などでコードのプロファイルを作成してみてください。驚くことでしょう。

私が書いていたアプリケーションでは、処理時間の 25% を占めていたのは SQL のパラメータ スニッフィングであることがわかりました。アプリケーションの開始時にパラメーターをスニッフィングするコマンド キャッシュを作成した後、速度が大幅に向上しました。

入れ子になった for ループを大量に実行していない限り、ループを変更してもパフォーマンスが大幅に向上することはないと思います。ゲームや多数のクランチング、科学的アプリケーションなどのリアルタイムアプリケーション以外に、そのような最適化が必要になるとは想像できません。

于 2012-05-21T16:46:53.293 に答える
2

はい。列挙子を考えてコレクションの要素にアクセスするのではなく、反復がインデックスベースであるため、クラシックforは a よりも少し高速です。foreach

       static void Main()
    {
        const int m = 100000000;
        //just to create an array
        int[] array = new int[100000000];
        for (int x = 0; x < array.Length; x++) {
            array[x] = x;
        }


        var s1 = Stopwatch.StartNew();           
        var upperBound = array.Length;
        for (int i = 0; i < upperBound; i++)
        {

        }
        s1.Stop();
        GC.Collect();
        var s2 = Stopwatch.StartNew();
        foreach (var item in array) { 

        }
        s2.Stop();
        Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds *
            1000000) / m).ToString("0.00 ns"));
        Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds *
            1000000) / m).ToString("0.00 ns"));
        Console.Read();

        //2.49 ns
        //4.68 ns

        // In Release Mode

        //0.39 ns
        //1.05 ns


}
于 2012-05-21T16:44:33.337 に答える