2010-05-03 3 views
29

.Net의 특정 컬렉션 유형에는 선택적 "초기 용량"생성자 매개 변수가 있습니다. 예 :컬렉션 유형의 초기 용량입니다 (예 : Dictionary, List

Dictionary<string, string> something = new Dictionary<string,string>(20); 

List<string> anything = new List<string>(50); 

MSDN에서이 개체의 기본 초기 용량을 찾지 못하는 것 같습니다.

사전에 12 개 정도의 항목 만 저장한다는 것을 알고 있다면 초기 용량을 20과 같이 설정하는 것이 좋지 않습니까?

제 생각에 용량이 적중 될 때마다 두 배가되는 StringBuilder의 경우와 같이 용량이 커지고 각 재 할당에는 많은 비용이 소요됩니다. 데이터를 보유 할 것으로 알고있는 크기로 사전 설정하지 않는 이유는 무엇입니까? 혹시라도 여분의 공간이 필요 하신가요? 초기 용량이 100이고, 내가 12 개 정도 밖에 필요하지 않다는 것을 안다면, 나머지 메모리는 아무 것도 할당되지 않은 것처럼 보입니다.

답변

60

기본값이 문서화되지 않은 경우 최적의 초기 용량이 구현 세부 사항이며 프레임 워크 버전간에 변경 될 수 있습니다. 즉, 특정 기본값을 가정하는 코드를 작성하면 안됩니다.

용량이 과부하 인 생성자 은 예상되는 항목 수보다 클수록을 더 잘 알고있는 경우를위한 것입니다. 예를 들어 50 개의 값으로 된 콜렉션을 작성하고이 값이 절대로 증가하지 않는다는 것을 알고있는 경우, 콜렉션을 50의 용량으로 초기화 할 수 있으므로 기본 용량이 더 낮 으면 크기를 조정할 필요가 없습니다.

그렇다면 반사경을 사용하여 기본값을 결정할 수 있습니다. 첫 번째 항목이 추가되면 예를 들어, .NET 4.0 (아마도 이전 버전뿐만 아니라),

  • 목록 <T> 그것이의 용량에 재 초기화되고, 0의 용량으로 초기화됩니다 4. 이후 용량에 도달 할 때마다 용량이 배가됩니다.

  • 사전 <T>도 0의 용량으로 초기화됩니다. 그러나 용량을 늘리기 위해 완전히 다른 알고리즘을 사용합니다. 항상 숫자를 소수로 늘려 용량을 늘립니다. 소스, 모두 List<T>Dictionary<TKey, TValue>의 기본 용량을 확인

+6

소수 계산은 입력 위치에 대한 해시 충돌 및 프로빙을 처리 할 가능성이 높습니다. 내부 메커니즘에 따라 각 해시에 하나의 값만 저장하면 보조 저장소 위치가 필요합니다. 프라임을 사용하지 않으면 삽입에 실패 할 수있는 해시를 잠재적으로 찾을 수 있습니다. – Matt

+5

사전 은 연결을 사용합니다. 프라임 숫자 테이블 크기는 잘못된 해시 함수를 보완합니다. 좋은 해시 함수는 임의의 분포를 생성합니다. 두 테이블 크기의 힘은 현대 해시 테이블에서 사용됩니다. (.net 해시 테이블은 자바 해시 테이블을 기반으로했습니다. 자바 해시 테이블은 프라임 숫자를 사용했기 때문에 해시 함수가 좋지 않은 시대에 사용했습니다. Microsoft는 해시 결합 방법을 제공하지 않기 때문에 많은 홈 내장 해시 함수는 빈약 한 배포를 생성하므로 해시 함수가 소수의 배수를 생성 할 때까지 때로는 소수 선택이 보상됩니다. –

8

당신이 크기를 알고있는 경우 0

+4

.Net 4.5에서는 추가 용량이 실제로 3입니다. 예, 기본 생성자는 용량 값이 0 인 오버로드 된 생성자를 호출하지만 생성자가 Initialize 메서드를 호출하면 크기가 3으로 설정됩니다. 사전은 제공된 용량보다 큰 다음 소수를 반환하는 HashHelpers.GetPrime (capacity)에 대한 호출에서 결정됩니다. 따라서 .Net 4.5에서 사전의 초기 용량은 3입니다. 목록의 기본 용량은 0이지만 목록에 첫 번째 항목을 추가하면 용량이 4로 변경됩니다. –

6

는, 다음을 말할 것입니다; 대부분의 "작은"경우에는 사소한 최적화가되지만 더 큰 컬렉션에는 유용합니다. 내가 주로 데이터의 "괜찮은"금액을 던지고있다면, 그때 그것을 할당, 복사 및 여러 배열을 수집하는 것을 피할 수있는 것처럼 걱정.

대부분의 컬렉션은 실제로 두 배 전략을 사용합니다.

1

ConcurrentDictionary (현재)의 또 다른 문제점으로 초기 크기를 설정하기 위해 생성자를 사용하면 성능이 저해되는 것으로 보입니다.

예 : here's some example code and benchmarks 시도했습니다.

내 컴퓨터에서 코드를 실행하여 비슷한 결과가 나타납니다.

즉, 초기 크기를 지정하면 객체를 추가 할 때 ConcurrentDictionary의 속도가 증가하지 않습니다. 기술적으로, 이어야한다고 생각합니다. 자체 크기를 조정할 시간이나 리소스가 필요하지 않기 때문입니다.

예, 정상적인 사전만큼 빠르게 실행되지 않을 수 있지만 초기 크기가 설정된 ConcurrentDictionary보다 일관성 있고 빠른 성능을 유지하도록 ConcurrentDictionary가 예상됩니다. 하나는 그것에 추가 될 항목의 수를 미리 알고 있습니다.

그래서 이야기의 도덕은 초기 크기가 항상 성능 향상을 보장한다고 설정하지 않습니다.