0

私のアプリのパフォーマンスがひどい理由を少し見てみました。私がしたのはデバッガーを2回一時停止することだけで、それを見つけました。

それが毎回私のコードを実行する実際的な理由はありますか?これを防ぐために私が知っている唯一の方法は、最後にToArray()を追加することです。すべてのコードを修正して、配列が返されることを確認する必要があると思いますか?

オンラインデモhttp://ideone.com/EUfJN

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
class Test
{

    static void Main()
    {
        string[] test = new string[] { "a", "sdj", "bb", "d444"};
        var expensivePrint = false;
        IEnumerable<int> ls = test.Select(s => { if (expensivePrint) { Console.WriteLine("Doing expensive math"); } return s.Length; });
        expensivePrint = true;
        foreach (var v in ls)
        {
            Console.WriteLine(v);
        }
        Console.WriteLine("If you dont think it does it everytime, lets try it again");
        foreach (var v in ls)
        {
            Console.WriteLine(v);
        }
    }
}

出力

Doing expensive math
1
Doing expensive math
3
Doing expensive math
2
Doing expensive math
4
If you dont think it does it everytime, lets try it again
Doing expensive math
1
Doing expensive math
3
Doing expensive math
2
Doing expensive math
4
4

7 に答える 7

4

列挙型は遅延評価します(必要な場合のみ)。選択の後に.ToList()を追加すると、評価が強制されます。

于 2012-07-25T22:11:38.673 に答える
3

Selectを選択すると、イテレータが繰り返されます。

結果の作成に費用がかかる場合は、結果を1回.ToList()してから、そのリストを使用できます。

List<int> resultAsList = ls.ToList();
// Use resultAsList in each of the foreach statements
于 2012-07-25T22:11:42.613 に答える
3

LINQには遅延評価方法Selectがあり、その1つです。

そして、foreach2回使用していて、値を2回出力します。

于 2012-07-25T22:13:50.887 に答える
1

クエリを作成するとき

IEnumerable<int> ls = test.Select(s => { if (expensivePrint) { Console.WriteLine("Doing expensive math"); } return s.Length; });

明らかに期待しているように、実際には実行せず、結果をキャッシュしません。これは「遅延実行」と呼ばれます。

クエリを作成するだけです。foreachクエリの実行は、クエリでステートメントが呼び出されたときに実際に行われます。

ToList()ただし、クエリでorToArray()またはSum()orまたはその種類の演算子を呼び出すとAverage()、すぐに実行されます。

クエリの結果を保持したい場合は、ToList()orを呼び出して配列またはリストにキャッシュしToArray()、作成されたクエリではなく、このリストまたは配列に列挙するのが最善の方法です。

于 2012-07-25T22:16:33.467 に答える
1

これは、Linqの延期された実行です。簡潔でありながら完全な説明が必要な場合は、次をお読みください。

http://weblogs.asp.net/dixin/archive/2010/03/16/understanding-linq-to-objects-6-deferred-execution.aspx

于 2012-07-25T22:16:38.057 に答える
1

のドキュメントを参照してくださいEnumerable.Select

このメソッドは、遅延実行を使用して実装されます。即時戻り値は、アクションの実行に必要なすべての情報を格納するオブジェクトです。このメソッドで表されるクエリは、GetEnumeratorメソッドを直接呼び出すか、Visual C#のforeachまたはVisualBasicのForEachを使用して、オブジェクトが列挙されるまで実行されません。

メソッドの結果を繰り返すことによりSelect、クエリが実行されます。 foreachその結果を繰り返す1つの方法です。 ToArray別です。


それが毎回私のコードを実行する実際的な理由はありますか?

はい、結果が延期されなかった場合、必要以上に多くの反復が実行されます。

IEnumerable<string> query = Enumerable.Range(0, 100000)
  .Select(x => x.ToString())
  .Where(s => s.Length == 6)
  .Take(5);
于 2012-07-26T00:02:45.277 に答える
0

私はあなたがあなたのためにそしてより良いパフォーマンスを与えるで.ToArray()あろうものを使うことを提案しますreturn int[]

int[]一度に宣言して作成し、List<T>実行時に1つずつ作成するための理由

int[] array = test.Select(s =>
{
   if (expensivePrint)
   {
     Console.WriteLine("Doing expensive math");
   }
   return s.Length;
}).ToArray();
于 2012-07-25T22:31:02.700 に答える