LINQ 식에서 다중 열거
발행: (2025년 12월 15일 오후 03:00 GMT+9)
4 min read
원문: Dev.to
Source: Dev.to
왜 다중 열거가 문제인가
- 반복 작업 – 각 열거는 시퀀스의 시작부터 시작하는 새로운 열거자를 생성합니다.
- 리소스 소비 – 데이터베이스, 웹 서비스 호출, 파일 읽기와 같은 쿼리의 경우, 각 열거가 비용이 많이 드는 작업을 다시 수행합니다.
- 예기치 않은 부작용 – 일부 열거자는 상태를 갖는 부작용(예: 로깅, 카운터)을 가지고 있어 여러 번 실행될 수 있습니다.
조기 물리화
반복 열거를 피하려면, 한 번 이상 순회할 필요가 있음을 알게 되는 즉시 시퀀스를 물리화합니다. 물리화는 지연된 IEnumerable를 구체적인 컬렉션(List, T[] 등)으로 변환하여 기본 쿼리를 다시 실행하지 않고 재사용할 수 있게 합니다.
// Lazy sequence
IEnumerable numbers = Enumerable.Range(1, 10);
// This will enumerate the sequence twice
foreach (int n in numbers) Console.WriteLine(n);
foreach (int n in numbers) Console.WriteLine(n);
ToList()(또는 ToArray())로 물리화하기
IEnumerable numbers = Enumerable.Range(1, 10);
List materializedNumbers = numbers.ToList(); // materialized once
// Both loops now use the same in‑memory list
foreach (int n in materializedNumbers) Console.WriteLine(n);
foreach (int n in materializedNumbers) Console.WriteLine(n);
모범 사례
| 권장 사항 | 이유 |
|---|---|
| 컬렉션을 여러 번 순회할 경우 조기에 물리화한다. | 원본 소스의 단일 열거를 보장합니다. |
ToList() 또는 ToArray() 를 사용해 IEnumerable를 구체 타입으로 변환한다. | 빠른 인덱스 접근을 제공하고 반복 쿼리 실행을 방지합니다. |
| 여러 번 열거될 메서드 매개변수 를 문서화한다. | 호출자에게 잠재적인 성능 비용을 알립니다. |
코드를 프로파일링 하여 동일 IEnumerable가 반복 열거되는 핫스팟을 찾는다. | 최적화 노력을 가장 중요한 부분에 집중할 수 있게 합니다. |
| 지연 실행을 이해한다 (파트 1 참조) | 지연된 쿼리에서 의도치 않은 다중 패스를 방지합니다. |
다중 열거가 특히 해로운 시나리오
- 데이터베이스 쿼리 – 각 열거가 SQL 명령을 다시 실행하여 여러 번 라운드 트립을 발생시킵니다.
- 외부 API 호출 – 재열거가 반복적인 네트워크 요청을 트리거할 수 있습니다.
- 파일 I/O – 파일을 여러 번 읽으면 I/O 대역폭이 낭비됩니다.
- 비싼 계산 – 복잡한 변환을 재계산하면 성능이 저하됩니다.
빠른 체크리스트
- 컬렉션을 한 번 이상 순회해야 하나?
- 그렇다면
ToList()/ToArray()를 한 번 호출하고 결과를 재사용한다. - 여러 번 열거될 매개변수를 문서화했는가?
- 숨겨진 다중 열거가 남아 있지 않은지 코드를 프로파일링했는가?
추가 자료
- 파트 1: Deferred Execution – The Essence of LINQ in C#
- 다가오는 글: LINQ Performance Optimization: 5 Patterns Every C# Developer Should Know