[C#] ToList ()를 호출 할 때 성능에 영향이 있습니까?

를 사용할 때 ToList()고려해야 할 성능 영향이 있습니까?

디렉토리에서 파일을 검색하는 쿼리를 작성했습니다. 이는 쿼리입니다.

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

그러나 List<>대신 작업을 좋아하기 때문에 …

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

따라서 이와 같은 변환을 결정할 때 고려해야 할 일종의 성능 영향이 있습니까? 아니면 많은 파일을 처리 할 때만 고려해야합니까? 무시할만한 전환입니까?



답변

IEnumerable.ToList()

예, IEnumerable<T>.ToList()성능에 영향을 미치지 만 성능에 중요한 작업에만주의를 기울여야 하는 O (n) 작업입니다.

ToList()작업은 사용 List(IEnumerable<T> collection)생성자를. 이 생성자는 배열의 사본을 만들어야합니다 (보다 일반적으로 IEnumerable<T>). 그렇지 않으면 원본 배열의 향후 수정 사항 T[]도 소스에서 변경되어 일반적으로 바람직하지 않습니다.

나는 이것을 거대한 목록으로 만 변화시킬 것이라고 반복하고 싶습니다. 메모리 덩어리를 복사하는 것은 매우 빠른 작업입니다.

편리한 팁 AsvsTo

LINQ에는 As(와 같은 AsEnumerable()) 및 To(과 같은 ToList()) 로 시작하는 몇 가지 방법이 있습니다. 로 시작하는 메소드는 To위와 같이 변환 이 필요하며 (즉, 성능에 영향을 줄 수 있음),로 시작하는 메소드는 As캐스트 또는 간단한 조작이 필요하지 않습니다.

추가 정보 List<T>

List<T>관심있는 경우 어떻게 작동 하는지에 대한 자세한 내용은 다음과 같습니다. 🙂

A는 List<T>또한 필요에 따라 크기를 조정해야하는 동적 배열라는 구조를 사용하여,이 크기 조정 이벤트 복사 새로운 배열로 기존 배열의 내용. 따라서 작은 크기로 시작하여 필요한 경우 크기가 늘어납니다 .

CapacityCount속성 의 차이점 입니다 List<T>. Capacity장면 뒤의 배열 크기를 나타내며, Count항목 수 List<T>는 항상 <= Capacity입니다. 따라서 항목을 목록에 추가하고을 지나서 늘리면 Capacity의 크기 List<T>가 두 배가되고 배열이 복사됩니다.


답변

toList ()를 호출 할 때 성능에 영향이 있습니까?

네 물론 이죠 이론적으로 i++는 성능에 영향을 미치므로 몇 번의 틱으로 인해 프로그램 속도가 느려집니다.

무엇을 .ToList합니까?

당신이 호출 할 때 .ToList, 코드 Enumerable.ToList()는 확장 메소드 인 호출 을한다 return new List<TSource>(source). 해당 생성자 에서 최악의 상황 에서 항목 컨테이너를 통해 하나씩 새 컨테이너에 추가합니다. 따라서 그 동작은 성능에 거의 영향을 미치지 않습니다. 응용 프로그램의 성능 병목이되는 것은 불가능합니다.

질문의 코드에 어떤 문제가 있습니까?

Directory.GetFiles폴더를 통해 모든 파일의 이름을 즉시 메모리에 반환 하면 string []에 많은 메모리가 소비되어 모든 것이 느려질 수 있습니다.

그때해야 할 일

때에 따라 다르지. 비즈니스 로직뿐만 아니라 폴더의 파일 크기가 항상 작다는 것을 보증하면 코드를 사용할 수 있습니다. 그러나 여전히 Directory.EnumerateFilesC # 4에서 게으른 버전을 사용하는 것이 좋습니다 . 이것은 쿼리와 훨씬 유사하며 즉시 실행되지 않으며 다음과 같이 쿼리를 더 추가 할 수 있습니다.

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

이름에 “myfile”이 포함 된 파일을 찾으면 경로 검색 이 중지 됩니다. 이것은 분명히 더 나은 성능을 가지고 .GetFiles있습니다.


답변

toList ()를 호출 할 때 성능에 영향이 있습니까?

그렇습니다. 확장 메소드를 사용하면 소스 콜렉션 에서 Enumerable.ToList()List<T>오브젝트를 구성 IEnumerable<T>하고 성능에 영향을줍니다.

그러나 이해 List<T>하면 성능에 미치는 영향이 큰지 판단하는 데 도움이 될 수 있습니다.

List<T>배열 ( T[])을 사용하여 목록의 요소를 저장합니다. 배열은 할당 된 후에는 확장 할 수 없으므로 너무 List<T>큰 배열을 사용하여 목록의 요소를 저장합니다. (가) 때 List<T>크기 이상으로 기본 배열을 성장하는 새로운 배열을 할당해야하고 이전 배열의 내용은 목록이 성장하기 전에 새로운 큰 배열에 복사 할 수 있습니다.

새로운 List<T>것이 만들어 지면 IEnumerable<T>두 가지 경우가 있습니다.

  1. 소스 컬렉션 은 ICollection<T>다음을 구현합니다 . 그런 다음 소스 컬렉션 ICollection<T>.Count의 정확한 크기를 가져 오는 데 사용되고 소스 컬렉션의 모든 요소가를 사용하여 백업 배열에 복사되기 전에 일치하는 백업 배열이 할당됩니다 ICollection<T>.CopyTo(). 이 작업은 매우 효율적이며 메모리 블록 복사를위한 일부 CPU 명령에 매핑 될 수 있습니다. 그러나 성능면에서 새 어레이에는 메모리가 필요하고 모든 요소를 ​​복사하려면 CPU주기가 필요합니다.

  2. 그렇지 않으면 소스 콜렉션의 크기를 알 수 없으며 열거 IEnumerable<T>자는 각 소스 요소를 새 소스에 한 번에 하나씩 추가하는 데 사용됩니다 List<T>. 처음에 백업 배열이 비어 있고 크기가 4 인 배열이 만들어집니다. 그런 다음이 배열이 너무 작 으면 크기가 두 배가되므로 4, 8, 16, 32 등과 같이 백업 배열이 커집니다. 백업 배열이 커질 때마다 다시 할당해야하고 지금까지 저장된 모든 요소를 ​​복사해야합니다. 이 작업은 정확한 크기의 배열을 즉시 만들 수있는 첫 번째 경우와 비교하여 훨씬 비용이 많이 듭니다.

    또한 소스 컬렉션에 33 개의 요소가 포함되어 있으면 메모리를 낭비하는 64 개의 요소 배열이 목록에 표시됩니다.

귀하의 경우 소스 컬렉션은 구현하는 배열 ICollection<T>이므로 소스 배열이 너무 크지 않으면 성능에 영향을 미치지 않습니다. 호출 ToList()하면 단순히 소스 배열을 복사하여 List<T>객체로 래핑 합니다. 두 번째 경우의 성능조차도 작은 컬렉션에 대해 걱정할 것이 아닙니다.


답변

“고려해야 할 성능 영향이 있습니까?”

정확한 시나리오의 문제는 무엇보다도 성능에 대한 실제 관심사가 드라이브 캐시의 하드 드라이브 속도와 효율성에 있다는 것입니다.

이러한 관점에서 볼 때 NO는 고려할 필요가 없다는 점에서 그 영향을 무시할 수 있습니다.

그러나 List<>생산성을 높이거나 알고리즘을 더 친숙하게 만들거나 다른 이점을 얻기 위해 구조 의 기능이 실제로 필요한 경우에만 해당됩니다 . 그렇지 않으면, 아무 이유없이 의도적으로 중요하지 않은 성능 적중을 추가하는 것입니다. 어떤 경우에는 당연히 그렇게해서는 안됩니다! 🙂


답변

ToList()새로운 List를 만들고 그 안에 요소를 넣습니다. 이는 관련 비용이 있음을 의미합니다 ToList(). 작은 컬렉션의 경우 비용이 많이 들지 않지만 큰 컬렉션을 보유하면 ToList를 사용할 때 성능이 저하 될 수 있습니다.

콜렉션을 List로 변환하지 않고 수행 할 수없는 작업이 아니면 일반적으로 ToList ()를 사용하지 마십시오. 예를 들어 컬렉션을 반복하려는 경우 ToList를 수행 할 필요가 없습니다.

데이터 소스 (예 : LINQ to SQL을 사용하는 데이터베이스)에 대해 쿼리를 수행하는 경우 지연된 실행을 수행하는 대신 LINQ to SQL과 함께 ToList를 사용할 때 (예 : 필요할 때 항목로드) ToList를 수행하는 비용이 훨씬 더 큽니다. 많은 시나리오에서) 데이터베이스에서 메모리로 항목을 즉시로드합니다.


답변

다음과 같이 비효율적입니다.

var list = new List<T>(items);

를 사용하는 생성자의 소스 코드를 디스 어셈블하면 IEnumerable<T>몇 가지 작업을 수행 할 수 있습니다.

  • 전화는 collection.Count, 그렇다면 collection이며 IEnumerable<T>, 그것은 실행을 강제 할 것이다. 경우 collection배열리스트 등이며 그되어야 O(1).

  • 경우 collection용구 ICollection<T>, 상기 사용 내부 배열 항목 저장할 ICollection<T>.CopyTo방법. 그것은 해야O(n)것, n컬렉션의 길이.

  • 경우 collection구현하지 않습니다 ICollection<T>, 그것은 컬렉션의 항목을 통해 반복되며, 내부 목록에 추가됩니다.

따라서 새로운 목록을 만들어야하기 때문에 더 많은 메모리를 소비 하며 최악의 경우O(n)collection 에는 각 요소의 복사본을 만들기 위해 반복됩니다 .


답변

파일 목록 검색 성능을 고려하면 ToList()무시할 수 있습니다. 그러나 실제로 다른 시나리오에는 해당되지 않습니다. 그것은 실제로 당신이 그것을 사용하는 곳에 달려 있습니다.

  • 배열, 목록 또는 다른 컬렉션을 호출 할 때 컬렉션의 복사본을로 만듭니다 List<T>. 여기에서의 성능은 목록의 크기에 따라 다릅니다. 정말로 필요할 때해야합니다.

    귀하의 예에서는 배열에서 호출합니다. 배열을 반복하고 항목을 하나씩 새로 만든 목록에 추가합니다. 따라서 성능 영향은 파일 수에 따라 다릅니다.

  • 를 호출 하면 (보통 쿼리) IEnumerable<T>구체화 합니다 IEnumerable<T>.