2010-07-23 8 views
5

저는 C#, Parallel.ForEach 및 .NET에 익숙하지 않습니다. 수천 개의 위치가 포함 된 검색을 병렬 처리하고 싶습니다. 각 위치에 대해 큰 원 거리를 계산합니다. 그것은 다른 코어로 퍼지기를 원하는 계산입니다. 내 질문은이 MSDN TPL example 같이 하나만 스레드 로컬 변수가있는 경우 어떻게합니까? 그 결과, 나는 Interlocked을보고, 옵션이 Add, CompareExchange, Decrement, Exchange, IncrementRead 인 것을 보았습니다. 그러나 저는 단지 추가, 증가, 감소 또는 동등성을 테스트하는 것이 아닙니다. 병렬로 실행되는 여러 스레드에서 객체를 반환하려는 경우 거리가 가장 짧습니다. 내 직감이 쉽게해야한다, 내가 Location 및 거리를 래핑하는 몇 가지 작은 개체를 만들 수 있어야하지만 어떻게 각 스레드에서 최상의 답변을 캡처합니까 다음 그들 사이의 최단 거리를 선택? 다음은 비 병렬 버전 :Parallel.ForEach를 사용하여 최소값 중에서 최소값 선택하기

Location findClosestLocation(Location myLocation, List<Location> allLocations) 
{ 
    double closest = double.MaxValue; 
    Location closestLoc = null; 
    foreach (Location aLoc in allLocations) 
    { 
    if (aLoc != myLocation) 
    { 
     double d = greatCircle(myLocation, aLoc); 
     if (d < closest) 
     { 
     closest = d; 
     closestLoc = aLoc; 
     } 
    } 
    } 
    return closestLoc; 
} 

내가 좋은 조언을 제공 듯 DDJ Blog Post를 참조했지만 나는 그것이 최선의 충고했다 궁금. 필자는 배열을 반복하는 루핑을 보았습니다.이 작업을 수행하는 데 더 기능적인 방법이 없는지 궁금합니다. 기능적 세계에서 나는 map, lambdamin을 사용할 것입니다.

답변

10

여기에 가장 쉬운 옵션은 PLINQ로 전환하는 것입니다 :

말했다되고 그건
Location findClosestLocation(Location myLocation, List<Location> allLocations) 
{ 
    return allLocations 
       .AsParallel() 
       .Min(location => greatCircle(myLocation, location)); 
} 

, 이것은 기본적으로 그냥 aggregation with parallel constructs입니다. Parallel 클래스를 계속 사용하려면 몇 가지 옵션이 있습니다. 하나의 옵션은 잠금을 사용하여 블록 내에서 자신을 동기화하는 것입니다. 전반적인 성능에 좋지 않은 영향을 미치므로 권장하지 않습니다.

더 나은 옵션은 로컬 상태를 제공하는 Parallel.ForEach 메서드를 사용하는 것입니다. 그들은 당신이 이것을 다음과 같이 다시 쓸 수있게 할 것입니다 :

Location findClosestLocation(Location myLocation, List<Location> allLocations) 
{ 
    double closest = double.MaxValue; 
    Location closestLoc = null; 
    object sync = new object(); 

    Parallel.ForEach<Location, Tuple<double,Location>(
     allLocations, 
    () => new Tuple(double.MaxValue, null), 
     (location, loopState, localState) => 
     { 
      double d = greatCircle(myLocation, aLoc); 
      if (d < localState.Item1) 
       return new Tuple(d, aLoc); 
      else 
       return localState; 
     }, 
     localState => 
     { 
      lock(sync) 
      { 
       if (localState.Item1 < closest) 
       { 
        closest = localState.Item1; 
        closestLoc = localState.Item2; 
       } 
      } 
     } 
); 
    return closestLoc; 
} 

나는 local state for aggregations in detail on my blog을 사용하여 표지합니다. 이것은 기본적으로 처리 요소 당 하나의 잠금 대신 스레드 당 하나의 잠금 작업으로 변경되므로 순진한 잠금 솔루션보다 훨씬 높은 처리량을 얻습니다.

+0

와우, 그것이 짧고 달콤합니다. 그것은 내 기능적인 마음을 노래하게합니다. 감사! – gknauth

+0

@ gknauth : 예 - 올바른/성능있는 Parallel.ForEach 옵션도 추가했습니다. 나는 ** 다른 옵션이 어떻게 작동 하는지를 배우고 그것을 이해하려고 노력하는 것을 추천한다. 하지만 이러한 작업의 대부분은 PLINQ를 사용하기 때문에 가치가 있습니다. –

+0

블로그에 나를 단서 주셔서 감사합니다. 멋지군요. 책을 쓰면, 내가 살 것이다! 또는 그것이 너무 많은 일이라면, 나는 당신에게 저녁을 사줄 것입니다. – gknauth

관련 문제