2010-02-06 2 views
1

C# 응용 프로그램을 프로파일 링하는 중입니다. 두 개의 스레드가 각각 Dictionary<>.ContainsKey() 두 개의 별개이지만 동일한 사전 (단 두 항목 만)에서 하나의 스레드보다 두 배 느린 단일 사전에 Dictionary<>.ContainsKey()을 10000 번 호출합니다.여러 스레드가 전체 사전 액세스 속도를 늦추 시나요?

JetBrains dotTrace라는 도구를 사용하여 "스레드 시간"을 측정하고 있습니다. 나는 똑같은 데이터의 복사본을 명시 적으로 사용하고 있기 때문에 내가 사용하고있는 synhronization 프리미티브가 없다. .NET이 장면 뒤에서 일부 동기화를 수행 할 가능성이 있습니까?

듀얼 코어 컴퓨터가 있고 세 개의 스레드가 실행 중입니다. 하나는 Semaphore.WaitAll()을 사용하여 차단되고 다른 하나는 우선 순위가 ThreadPriority.Highest 인 두 개의 새 스레드에서 작업이 수행됩니다.

실제로 코드를 병렬로 실행하지 않고 릴리스 빌드를 사용하지 않는 것과 같은 명백한 범인은 배제되었습니다.

편집 :

사람들이 코드를 원합니다. 좋아, 그럼 :

private int ReduceArrayIteration(VM vm, HeronValue[] input, int begin, int cnt) 
    { 
     if (cnt <= 1) 
      return cnt; 

     int cur = begin; 

     for (int i=0; i < cnt - 1; i += 2) 
     { 
      // The next two calls are effectively dominated by a call 
      // to dictionary ContainsKey 
      vm.SetVar(a, input[begin + i]); 
      vm.SetVar(b, input[begin + i + 1]); 
      input[cur++] = vm.Eval(expr); 
     } 

     if (cnt % 2 == 1) 
     { 
      input[cur++] = input[begin + cnt - 1]; 
     } 

     int r = cur - begin; 
     Debug.Assert(r >= 1); 
     Debug.Assert(r < cnt); 
     return r; 
    } 

    // From VM 
    public void SetVar(string s, HeronValue o) 
    { 
     Debug.Assert(o != null); 
     frames.Peek().SetVar(s, o); 
    } 

    // From Frame 
    public bool SetVar(string s, HeronValue o) 
    { 
     for (int i = scopes.Count; i > 0; --i) 
     { 
      // Scope is a derived class of Dictionary 
      Scope tbl = scopes[i - 1]; 
      if (tbl.HasName(s)) 
      { 
       tbl[s] = o; 
       return false; 
      } 
     } 
     return false; 
    } 

지금 여기 지체 될 수있는 스레드 산란 코드입니다 :

public static class WorkSplitter 
{ 
    static WaitHandle[] signals; 

    public static void ThreadStarter(Object o) 
    { 
     Task task = o as Task; 
     task.Run(); 
    } 

    public static void SplitWork(List<Task> tasks) 
    { 
     signals = new WaitHandle[tasks.Count]; 
     for (int i = 0; i < tasks.Count; ++i) 
      signals[i] = tasks[i].done; 
     for (int i = 0; i < tasks.Count; ++i) 
     { 
      Thread t = new Thread(ThreadStarter); 
      t.Priority = ThreadPriority.Highest; 
      t.Start(tasks[i]); 
     } 
     Semaphore.WaitAll(signals); 
    }   
} 
+0

이 스레드 및 사전을 사용하여 해결하려는 실제 문제를 설명해 주시겠습니까? –

+0

인터프리터 작성 및 특정 벡터 작업을 병렬 처리해야합니다. – cdiggins

+0

코드를 게시해야합니다. – ChaosPandion

답변

4

사전 (이없는)의 모든 잠금이 있었다하더라도, 그것은 영향을주지 수는 측정은 각 스레드가 별도의 스레드를 사용하고 있기 때문에 가능합니다. 이 테스트를 10,000 번 실행하면 신뢰할 수있는 타이밍 데이터를 얻는 데 충분하지 않으며 ContainsKey()는 20 나노초 정도 밖에 걸리지 않습니다. 아티팩트 일정을 피하려면 최소한 수백만 회는 필요합니다.

+0

문제는 10,000 회 반복이 빠르다는 것입니다. 더 많은 반복에 대한 타이밍을 얻는 것은 내가 신경 쓰지 않는 경우를 위해 최적화 될 것입니다. 이론적으로는 병렬화가 가능해야하는 작업을 위해 두 번째 코어를 완전히 활용하려고하는 악마가 있습니다. – cdiggins

+2

스레드가 200 마이크로 초 동안 만 실행될 때 병렬 작업을 기대할 수있는 방법을 모르겠습니다. 두 스레드가 정확히 같은 시간에 시작되게하려면 운이 좋을 것입니다. –

+0

스레드가 그보다 훨씬 오래 작동하므로 계측없이 전체 테스트에 약 100msec가 소요됩니다. 내 프로파일 러는 두 번째로 인기있는 핫스팟은 Dictionary 내부에있는 "FindEntry"라고 말합니다. 한 스레드로 테스트 할 때 296msec가 소요되고 두 스레드로 테스트에 577msec가 소요됩니다. 이것은 수십 번의 시련에서 실제로 일관되고 내 마음을 날려 버립니다. – cdiggins

관련 문제