2016-10-04 12 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 subtotal'問題を修正しても機能しません。あなたは非常に明白な競争状態を持っています。常に値を更新して読み込みます。 – Jonesopolis

+0

どのように共有変数を追跡することができますか? – BobSwanson

+1

@BobSwanson最初に和を並列化しないでください。単一のスレッドで値を合計するよりもはるかに遅くなります。はるかに速くなるだけでなく、エラーも発生しやすく、メンテナンスも簡単です。 – Servy

答えて

2

共有は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

おそらくあなたは+ =?あなたはAgeの正の価値に共有するように設定していますか? –

+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またはlongではなく10進数でない場合は、代わりにlock()を使用しますか? – BobSwanson

0

この

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

を試してみて結果が同じになり、より少ないコードが使用されます。

関連する問題