web-dev-qa-db-ja.com

ToList()を呼び出すときにパフォーマンスに影響はありますか?

ToList()を使用する場合、考慮する必要があるパフォーマンスへの影響はありますか?

ディレクトリからファイルを取得するクエリを作成していました。これはクエリです。

string[] imageArray = Directory.GetFiles(directory);

ただし、代わりにList<>を使用するのが好きなので、...

List<string> imageList = Directory.GetFiles(directory).ToList();

だから、このような変換を行うことを決定するときに考慮する必要があるパフォーマンスへの何らかの影響がありますか?または多数のファイルを扱うときにのみ考慮する必要がありますか?これは無視できる変換ですか?

124
Cody

IEnumerable.ToList()

はい、 IEnumerable<T>.ToList() はパフォーマンスに影響を与えます。これはO(n)操作です。ただし、パフォーマンスが重要な操作。

ToList()操作は List(IEnumerable<T> collection) コンストラクターを使用します。このコンストラクターは、配列(より一般的にはIEnumerable<T>)のコピーを作成する必要があります。そうしないと、元の配列の将来の変更がソースT[]で変更され、これも一般的に望ましくありません。

繰り返しますが、これは巨大なリストとの違いを生むだけです。メモリのチャンクをコピーするのは非常に高速な操作です。

便利なヒント、As vs To

LINQには、AsAsEnumerable() など)およびToToList() など)で始まるメソッドがいくつかあります。 Toで始まるメソッドは上記のような変換を必要とします(つまり、パフォーマンスに影響する可能性があります)。また、Asで始まるメソッドは必要なく、キャストまたは単純な操作を必要とします。

List<T>の追加詳細

興味のある場合にList<T>がどのように機能するかについてもう少し詳しく説明します:)

List<T>は、動的配列と呼ばれる構造も使用します。これは、要求に応じてサイズを変更する必要があります。このサイズ変更イベントは、古い配列の内容を新しい配列にコピーします。そのため、小さな値から始まり、 必要に応じてサイズが大きくなります

これは、 CapacityCount の属性の違いです List<T>Capacityは舞台裏の配列のサイズを示し、CountList<T>のアイテム数であり、常に<= Capacityです。そのため、アイテムがリストに追加され、Capacityを超えると、List<T>のサイズが2倍になり、配列がコピーされます。

159
Daniel Imms

ToList()を呼び出すときにパフォーマンスに影響はありますか?

はい、もちろん。理論的にはi++でさえパフォーマンスに影響を与えます。それはおそらく数ティックの間プログラムを遅くします。

.ToListは何をしますか?

.ToListを呼び出すと、コードはEnumerable.ToList()を呼び出す拡張メソッドであるreturn new List<TSource>(source)を呼び出します。対応するコンストラクターでは、最悪の状況の下でアイテムコンテナーを通過し、それらを1つずつ新しいコンテナーに追加します。そのため、その動作はパフォーマンスにほとんど影響しません。アプリケーションのパフォーマンスのボトルネックになることは不可能です。

質問のコードの何が問題なのか

Directory.GetFilesはフォルダーを通過し、すべてのファイル名をすぐにメモリーに返しますメモリーのすべてが遅くなります。

そのとき何をすべきか

場合によります。 (ビジネスロジックと同様に)フォルダー内のファイル量が常に少ないことを保証する場合、コードは受け入れられます。ただし、C#4ではDirectory.EnumerateFilesのレイジーバージョンを使用することをお勧めします。これはクエリに似ており、すぐには実行されません。次のようにクエリを追加できます。

Directory.EnumerateFiles(myPath).Any(s => s.Contains("myfile"))

名前に「myfile」が含まれるファイルが見つかるとすぐに、パスの検索を停止します。これは明らかに.GetFilesよりも優れたパフォーマンスを発揮します。

34
Cheng Chen

ToList()を呼び出すときにパフォーマンスに影響はありますか?

はいあります。拡張メソッドEnumerable.ToList()を使用すると、List<T>ソースコレクションから新しいIEnumerable<T>オブジェクトが作成されますが、これはもちろんパフォーマンスに影響します。

ただし、List<T>を理解すると、パフォーマンスへの影響が大きいかどうかを判断するのに役立ちます。

List<T>は配列(T[])を使用してリストの要素を格納します。割り当てられた配列は拡張できないため、List<T>はサイズの大きい配列を使用してリストの要素を格納します。 List<T>が基になる配列のサイズを超えて大きくなると、新しい配列を割り当て、リストを大きくする前に古い配列の内容を新しい大きな配列にコピーする必要があります。

新しいList<T>IEnumerable<T>から構築される場合、2つのケースがあります。

  1. ソースコレクションはICollection<T>を実装します。その後、ICollection<T>.Countを使用してソースコレクションの正確なサイズを取得し、ICollection<T>.CopyTo()を使用してソースコレクションのすべての要素をバッキング配列にコピーする前に、一致するバッキング配列を割り当てます。この操作は非常に効率的で、おそらくメモリブロックをコピーするためのCPU命令にマップされます。ただし、パフォーマンスの観点から、新しいアレイにはメモリが必要であり、すべての要素をコピーするにはCPUサイクルが必要です。

  2. それ以外の場合、ソースコレクションのサイズは不明であり、IEnumerable<T>の列挙子を使用して、各ソース要素を1つずつ新しいList<T>に追加します。最初、バッキング配列は空で、サイズ4の配列が作成されます。次に、この配列が小さすぎる場合、サイズが2倍になり、バッキング配列がこのように大きくなります。4、8、16、32など。この操作は、正しいサイズの配列をすぐに作成できる最初のケースに比べてはるかにコストがかかります。

    また、ソースコレクションに33個の要素が含まれている場合、リストは64個の要素の配列を使用してメモリを浪費します。

あなたの場合、ソースコレクションはICollection<T>を実装する配列なので、ソース配列が非常に大きくない限り、パフォーマンスへの影響は心配する必要はありません。 ToList()を呼び出すと、ソース配列がコピーされ、List<T>オブジェクトにラップされます。 2番目のケースのパフォーマンスでさえ、小さなコレクションでは心配する必要はありません。

15

「考慮する必要があるパフォーマンスへの影響はありますか?」

正確なシナリオの問題は、何よりもまず、パフォーマンスに関する本当の懸念は、ハードドライブの速度とドライブのキャッシュの効率にあるということです。

その観点から、その影響は、NO考慮する必要がないという点まで、ごくわずかです。

ただし、List<>構造体の機能が本当に必要な場合にのみ、生産性を高めるか、アルゴリズムをより使いやすくするか、その他の利点を得ることができます。それ以外の場合は、まったく理由なく、意図的に重要でないパフォーマンスヒットを追加するだけです。その場合、当然、あなたはそれをすべきではありません! :)

5
jross

ToList()は新しいリストを作成し、その中に要素を配置します。つまり、ToList()の実行に関連するコストがかかります。小さいコレクションの場合、それほど大きなコストにはなりませんが、ToListを使用する場合、膨大なコレクションがあるとパフォーマンスが低下する可能性があります。

通常、ToList()は、コレクションをリストに変換せずに作業を実行できない場合を除き、使用しないでください。たとえば、コレクションを反復処理するだけの場合、ToListを実行する必要はありません。

LINQ to SQLを使用するデータベースなどのデータソースに対してクエリを実行している場合、ToListを使用する場合、遅延実行ではなくLINQ to SQLでToListを使用する場合、つまり必要に応じてアイテムをロードするため、ToListのコストははるかに高くなります多くのシナリオで)データベースからメモリにアイテムを即座にロードします

4
Haris Hasan

ファイルリストの取得のパフォーマンスを考慮すると、ToList()は無視できます。しかし、実際には他のシナリオではありません。それは本当にあなたがそれを使用している場所に依存します。

  • 配列、リスト、またはその他のコレクションを呼び出す場合、コレクションのコピーをList<T>として作成します。ここでのパフォーマンスは、リストのサイズに依存します。本当に必要なときに行うべきです。

    例では、配列で呼び出します。配列を反復処理し、新しく作成されたリストにアイテムを1つずつ追加します。したがって、パフォーマンスへの影響はファイルの数に依存します。

  • IEnumerable<T>を呼び出す場合、マテリアライズIEnumerable<T>(通常はクエリ)を呼び出します。

2

ToListは新しいリストを作成し、元のソースから新しく作成されたリストに要素をコピーするため、元のソースから要素をコピーするだけで、ソースのサイズに依存します

2
TalentTuner