2016-10-04 2 views
0

하위 코드가있어서 어떻게 공유 변수를 업데이트 할 수 있습니까? 공유 어떤 이유Parallel.ForEach가 공유 변수를 업데이트하지 않습니다.

 List<Person> list = new List<Person> {new Person {Age = 1}, new Person {Age = 2}, new Person {Age = 5}}; 
     long total = 0; 

     Parallel.ForEach(list,() => 0, (person, loop, subtotal) => 
      { 
       Add(person, subtotal); 
       return subtotal; 
      }, 

      finalResult => Interlocked.Add(ref total, finalResult) 
     ); 

    public static void Add(Person person, int shared) 
    { 
     // Do some work 
     shared =+ person.Age; 
    } 

는 매개 변수에게 심판을해야하므로 ... 정수 값 유형이있다는 "일반"C# 코드에서 작동하지 않을 것입니다 0

+0

'ref 부분합'문제를 수정하더라도이 작업이 진행되지 않습니다. 당신은 매우 명백한 경쟁 조건을 가지고 있습니다. 값을 지속적으로 업데이트하고 읽는 중입니다. – Jonesopolis

+0

그러면 어떻게 공유 변수를 추적 할 수 있습니까? – BobSwanson

+1

@BobSwanson 처음부터 합계를 병렬 처리하지 마십시오. 단일 스레드에서 값을 합계하는 것보다 훨씬 느립니다. 훨씬 빠르다는 것 외에도, 더 간단하고, 오류가 발생하기 쉽고 유지 보수가 용이합니다. – Servy

답변

2

Shared는 0으로 전송되어 값으로 전달 되었기 때문에 0으로 되돌려집니다. ref 키워드를 사용해야하거나 다른 방식 (정적 변수)으로이 동작을 처리해야합니다.

public static void Add(Person person, ref int shared) 
{ 
    // Do some work 
    shared =+ person.Age; 
} 

'+ ='대신 '= +'를 사용하는 것과 같은 문제가있는 것으로 보입니다.

public static void Add(Person person, ref int shared) 
{ 
    // You likely meant to do this. 
    shared += person.Age; 
} 
+0

이제는 마지막 하나를 반환합니다. 모든 연령대의 합계가 없습니다 – BobSwanson

+0

아마 + =? 당신은 나이의 긍정적 인 가치를 공유하도록 설정하고 있습니까? –

+0

아, 그게 효과가있어, 자물쇠가 필요해? 그것이 공유 되었기 때문에? – BobSwanson

0

같은 이유로 다시 온다 매개 변수. 그렇지 않으면, 당신은 단지 로컬 복사본을 증가시키고 있습니다. 또한 + = 대신 Interlocked.Increment를 사용해야합니다. 그렇지 않으면 + = 반드시 원자가 아니기 때문에 스레딩 문제가 발생할 수 있습니다.

2

당신은 조금에게 예상 된 결과를 코드를합니다 변경 :

static void Main(string[] args) 
{ 
    List<Person> persons = new List<Person> 
    { 
     new Person { Age = 1 }, 
     new Person { Age = 2 }, 
     new Person { Age = 5 } 
    }; 

    long total = 0; 

    Parallel.ForEach(persons, person => Add(person, ref total)); 

    Console.WriteLine(total); 
    Console.ReadKey(); 
} 

public static void Add(Person person, ref long shared) 
{ 
    // since here you access a shared variabe, we 
    // can use the Interlocked class in order our operation 
    // to be atomic. 
    Interlocked.Add(ref shared, person.Age); 
} 
+0

전체가 잘못되었습니다. 매번 다를 때 – BobSwanson

+0

@BobSwanson 당신이 맞습니다! 내 편집을 참조하십시오. – Christos

+0

내 공유가 int가 아니거나 길지만 십진수가 아닌 경우 대신 lock()을 사용합니까? – BobSwanson

0

int sum = list.AsParallel().Sum(person => person.Age); 

이 결과는 같은과 적은 코드가 사용됩니다 될 것입니다보십시오.