3

どちらがより効率的ですか?

//Option 1
foreach (var q in baseQuery)
{
  m_TotalCashDeposit += q.deposit.Cash
  m_TotalCheckDeposit += q.deposit.Check
  m_TotalCashWithdrawal += q.withdraw.Cash
  m_TotalCheckWithdrawal += q.withdraw.Check
}

//Option 2
m_TotalCashDeposit = baseQuery.Sum(q => q.deposit.Cash);
m_TotalCheckDeposit = baseQuery.Sum(q => q.deposit.Check);
m_TotalCashWithdrawal = baseQuery.Sum(q => q.withdraw.Cash);
m_TotalCheckWithdrawal = baseQuery.Sum(q => q.withdraw.Check);

私が求めているのは、 Sum を呼び出すと、基本的にリストが列挙されるということですよね?つまり、Sum を 4 回呼び出すと、リストを 4 回列挙しているのではないでしょうか。代わりに foreach を実行する方が効率的ではないので、リストを 1 回列挙するだけで済みますか?

4

2 に答える 2

6

状況によって異なりますが、そうでない場合もあります。

知る唯一の確実な方法は、実際にそれを測定することです。

これを行うには、BenchmarkDotNetを使用します。これは、 LINQPadまたはコンソールアプリケーションで実行できる例です。

void Main()
{
    BenchmarkSwitcher.FromAssembly(GetType().Assembly).RunAll();
}

public class Benchmarks
{
    [Benchmark]
    public void Option1()
    {
//        foreach (var q in baseQuery)
//        {
//            m_TotalCashDeposit += q.deposit.Cash;
//            m_TotalCheckDeposit += q.deposit.Check;
//            m_TotalCashWithdrawal += q.withdraw.Cash;
//            m_TotalCheckWithdrawal += q.withdraw.Check;
//        }
    }

    [Benchmark]
    public void Option2()
    {
//        m_TotalCashDeposit = baseQuery.Sum(q => q.deposit.Cash);
//        m_TotalCheckDeposit = baseQuery.Sum(q => q.deposit.Check);
//        m_TotalCashWithdrawal = baseQuery.Sum(q => q.withdraw.Cash);
//        m_TotalCheckWithdrawal = baseQuery.Sum(q => q.withdraw.Check);
    }
}

BenchmarkDotNetは、パフォーマンスを測定するための強力なライブラリであり、統計的に正しいアプローチと方法を使用し、JITtingやGCなども考慮に入れるため、単にStopwatchを使用するよりもはるかに正確です。


私は年をとって賢くなったので、ストップウォッチを使用することはもはや信じられませんが、パフォーマンスを測定するための良い方法です。グーグルや同様のリンクがストップウォッチを使用してパフォーマンスを測定する方法を探している人々をここに導く可能性があるため、古い答えを削除しませんが、上記のより良いアプローチを追加したことを願っています。

以下の元の回答

それを測定するための簡単なコード:

Stopwatch sw = new Stopwatch();
sw.Start();
// your code here
sw.Stop();
Debug.WriteLine("Time taken: " + sw.ElapsedMilliseconds + " ms");
sw.Reset(); // in case you have more code below that reuses sw

JITingがタイミングに大きな影響を与えないように、コードを複数回実行する必要があります。

于 2009-08-12T16:57:54.957 に答える
2

I went ahead and profiled this and found that you are correct.

Each Sum() effectively creates its own loop. In my simulation, I had it sum SQL dataset with 20319 records, each with 3 summable fields and found that creating your own loop had a 2X advantage.

I had hoped that LINQ would optimize this away and push the whole burden on the SQL server, but unless I move the sum request into the initial LINQ statement, it executes each request one at a time.

于 2009-08-12T17:17:38.083 に答える