C#

1

에서 ConcurrentDictionary.Count의 성능을 향상시키는 방법 최근에 SortedDictionarySortedList 사이에서 선택하고 SortedList에 정착해야했습니다.C#

그러나 이제는 수천 번 호출되는 함수/메서드를 사용하여 SortedList.Count를 검사 할 때 내 C# 프로그램이 느려지는 것을 발견했습니다.

보통 내 프로그램은 35ms 이내에 10,000 번 기능을 호출하지만 SortedList.Count을 사용하는 동안은 기본적으로 10 배 느린 300-400ms로 느려졌습니다.

나는 또한 SortedList.Keys.Count을 시도했지만, 이것은 내 성능을 또 다른 10 배나 3000 밀리 초로 줄였습니다.

I have only ~5000 keys/objects in SortedList<DateTime, object_name>. 쉽게 정렬 된 목록에서 데이터를 SortedList[date] (in 35 ms)까지 즉시 검색 할 수 있으므로 목록 구조 또는 해당 개체의 보유 관련 문제를 발견하지 못했습니다.

이 성능은 정상입니까?

목록에서 레코드 수를 얻거나 목록이 채워 졌는지 확인하기 위해 사용할 수있는 다른 방법은 무엇입니까? (내가 지금 할 수있는 별도의 추적 플래그를 추가 외에)

수정 : 미안 해요, 난 실제로 사용하고 있습니다, ConcurrentDictionary<string, SortedList<DateTime, string>> dict_list = new ConcurrentDictionary<string, SortedList<DateTime, string>>(); 을 그리고 다양한 장소에서 다양한 수를 가지고 때로는 목록에있는 항목을 확인하고 ConcurrentDicitonary에서 다른 시간. 그래서이 문제는 ConcurrentDicitonary에 적용됩니다. 동시성을 사용하지 않고이 작업을 확인하기 위해 빠른 테스트 코드를 작성했습니다. 350 밀리 초가 소요됩니다. 다음은 350 MS 보여 ConcurrentDicitonary 테스트입니다 :

public static void CountTest() 
{ 
    //Create test ConcurrentDictionary 
    ConcurrentDictionary<int, string> test_dict = new ConcurrentDictionary<int, string>(); 
    for (int i = 0; i < 50000; i++) 
    { 
     test_dict[i] = "ABC"; 
    } 

    //Access .Count property 10,000 times 
    int tick_count = Environment.TickCount; 
    for (int i = 1; i <= 10000; i++) 
    { 
     int dict_count = test_dict.Count; 
    } 

    Console.WriteLine(string.Format("Time: {0} ms", Environment.TickCount - tick_count)); 
    Console.ReadKey(); 
} 
+0

실제 질문은 다음과 같습니다. 자주? 너무 오래 걸린다 고 생각하면하지 마세요. 대신 변수에 저장하십시오. – HimBromBeere

+0

목록이 채워 졌는지 확인하려는 경우 SortedList.Any()를 사용할 수 없습니까? – spersson

+8

SortedList.Count는 전용 변수의 값을 반환하지만 느려질 수는 없습니다.LINQ Count() 메서드를 사용하고 있지 않습니까? – Evk

답변

2

음, ConcurrentDictionary<TKey, TValue> 한 번에 많은 스레드 제대로 작동해야합니다, 그래서 일부 동기화 오버 헤드를 필요로한다. Count 속성에 대한

소스 코드 : 기존 코드를 리팩토링 할 필요가 같은 https://referencesource.microsoft.com/#mscorlib/system/Collections/Concurrent/ConcurrentDictionary.cs,40c23c8c36011417

public int Count 
    { 
     [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "ConcurrencyCop just doesn't know about these locks")] 
     get 
     { 
      int count = 0; 

      int acquiredLocks = 0; 
      try 
      { 
       // Acquire all locks 
       AcquireAllLocks(ref acquiredLocks); 

       // Compute the count, we allow overflow 
       for (int i = 0; i < m_tables.m_countPerLock.Length; i++) 
       { 
        count += m_tables.m_countPerLock[i]; 
       } 

      } 
      finally 
      { 
       // Release locks that have been acquired earlier 
       ReleaseLocks(0, acquiredLocks); 
      } 

      return count; 
     } 
    } 

보인다. 코드를 제공하지 않으므로 최적화 할 수있는 것을 알려 드릴 수 없습니다.

+0

글쎄요, 이것은 ConcurrentDictionary >'에있는 여러 소스의 데이터를 캐싱하는 대규모 시스템입니다. 데이터가 이미로드되어 있는지 확인 중입니다. 하지만 전반적으로 나는 ConcurrentDictionary와 SortedList를 다양한 장소에서 다양한 방식으로 사용하여 동시성의 의미를 이해합니다. 그러나 느린 백작이 나를 던져 버렸고 가장 간단한 대체품을 찾고 있습니다. –

+0

참고 몇 가지를 추가 한 백작을 제외하고 모든 것이 훌륭하게 수행되는 것은 이상한 것처럼 보입니다. 몇 주 전에 시스템을 크롤링 속도가 느려지는 이유를 찾기 위해 며칠을 보냅니다. 다른 사람들도 카운트를 사용하는 것만으로도 성능에 심각한 영향을 줄 수 있음을 깨닫지 못할 수도 있습니다. –

+0

@KonRad : 아직 이해가 안가요. 각 제공자는'Count'를 호출하고,'Count> 0'이 어떤 entires를 적재하려고한다면? – apocalypse

0

성능이 중요한 코드의 경우 잠금 구현이 있으므로 ConcurrentDictionary.Count 속성을 사용하지 않는 것이 좋습니다. 대신 카운트를 직접 수행하려면 Interlocked.Increment을 사용할 수 있습니다.

0

article이 대신 호출하는 것이 좋습니다 :

dictionary.Skip(0).Count() 

카운트 곧 메소드가 리턴에서 통화 등으로 무효가 될 수 있습니다. 예를 들어, 자물쇠가없는 열거 자와 같은 대체 방법을 사용할 수 있습니다. 추적을 위해 로그에 카운트를 쓰려면