2010-05-05 5 views
5

Text - File의 데이터를 Dictionary 개체에 저장하는 C# -Application이 있습니다. 저장할 데이터의 양은 다소 클 수 있으므로 항목을 삽입하는 데 많은 시간이 걸립니다. 사전에있는 많은 항목을 사용하면 사전에 대한 데이터를 저장하는 내부 배열 크기를 조정하기 때문에 더 악화 될 수 있습니다. 그래서 추가 될 항목의 양으로 사전을 초기화했지만 속도에는 영향을 미치지 않습니다. 내 테스트에서많은 양의 항목에 대한 Dictionary.Add의 런타임이 높습니다.

private Dictionary<IdPair, Edge> AddEdgesToExistingNodes(HashSet<NodeConnection> connections) 
{ 
    Dictionary<IdPair, Edge> resultSet = new Dictionary<IdPair, Edge>(connections.Count); 

    foreach (NodeConnection con in connections) 
    { 
    ... 
    resultSet.Add(nodeIdPair, newEdge); 
    } 

    return resultSet; 
} 

, 나는 ~ 300K 항목을 삽입합니다

여기 내 기능입니다. ANTS Performance Profiler로 실행 시간을 확인한 결과 필요한 크기로 사전을 초기화 할 때 resultSet.Add (...)의 평균 시간이 변경되지 않는다는 것을 알았습니다. 새 사전()을 사용하여 사전을 초기화 할 때와 같습니다. (각 Add에 대해 평균 약 0.256ms). 이것은 확실히 사전에있는 데이터의 양에 기인합니다 (나는 원하는 크기로 초기화했습니다). 처음 20k 항목의 경우 Add에 대한 평균 시간은 각 항목에 대해 0.03ms입니다.

추가 작업을 더 빠르게하는 방법에 대해 알고 싶습니다.

public struct IdPair 
{ 
    public int id1; 
    public int id2; 

    public IdPair(int oneId, int anotherId) 
    { 
    if (oneId > anotherId) 
    { 
     id1 = anotherId; 
     id2 = oneId; 
    } 
    else if (anotherId > oneId) 
    { 
     id1 = oneId; 
     id2 = anotherId; 
    } 
    else 
     throw new ArgumentException("The two Ids of the IdPair can't have the same value."); 
    } 
} 
+6

'IdPair' 클래스에서'Equals'와'GetHashCode'를 오버라이드하고 있습니까? 그렇다면,'GetHashCode' 알고리즘은 적절한 해시 분포를 생성합니까? – LukeH

+0

IdPair는 생성자가있는 struct입니다. 나는 내 질문에 그것을 더했다 – Aaginor

답변

9

, 당신은 같음() 및 GetHashCode()의 기본 구현을 얻을 :

내 제안 구현, 그것은 정확히 원하는 당신이/필요하지 않을 수 있습니다. 다른 사람들이 지적했듯이, 이것은 반사를 사용하므로 매우 효율적이지는 않지만 반사가 문제라고 생각하지 않습니다.

내 생각에, 기본 구현이 모든 멤버의 간단한 XOR을 반환하는 경우 (예 : hash (a, b) =) GetHashCode() = 해시 (b, a)). ValueType.GetHashCode()가 구현 된 방법에 대한 문서를 찾을 수 없지만 추가하려고 시도해주세요.

public override int GetHashCode() { 
    return oneId << 16 | (anotherId & 0xffff); 
} 

더 좋을 수도 있습니다.

+0

완벽한 추측! 작은 해시 함수는 각 Add에 대해 Average에 ~ 0.02ms의 작업 시간을 줄입니다. – Aaginor

7

IdPairstruct, 당신은 Equals 또는 GetHashCode를 오버라이드 (override)하지 않은 : 사전에

감사합니다, 프랭크

은 여기 내 IdPair - 구조체이다. 즉, 해당 메소드의 기본 구현이 사용됩니다.

값 유형의 경우 기본 구현 EqualsGetHashCode은 리플렉션을 사용하므로 성능이 저하 될 수 있습니다. 메서드를 직접 구현하여 해당 메서드가 도움이되는지 확인하십시오. 당신이 구조체를 가지고 있기 때문에

public struct IdPair : IEquatable<IdPair> 
{ 
    // ... 

    public override bool Equals(object obj) 
    { 
     if (obj is IdPair) 
      return Equals((IdPair)obj); 

     return false; 
    } 

    public bool Equals(IdPair other) 
    { 
     return id1.Equals(other.id1) 
      && id2.Equals(other.id2); 
    } 

    public override int GetHashCode() 
    { 
     unchecked 
     { 
      int hash = 269; 
      hash = (hash * 19) + id1.GetHashCode(); 
      hash = (hash * 19) + id2.GetHashCode(); 
      return hash; 
     } 
    } 
} 
+0

많은 감사, 루크. (표준) 해시 함수가 문제였습니다. 당신의 솔루션으로, 나는 각 Add에 대해 평균 ~ 0.03 ms의 작업 시간을 줄였습니다. 그럼에도 불구하고 erikkallens 솔루션보다 조금 느리지 만 이전보다 훨씬 개선되었습니다. 주목할만한 점은 미리 사전의 크기를 설정하면 아무런 효과가없는 것처럼 보입니다. – Aaginor

관련 문제