2

始める前に、ここで棒の先が間違っているような気がすることを述べておかなければなりません。しかし、とにかくここに行きます:

次のクラスがあるとします。

public class SomeObject {
    public int SomeInt;
    private SomeObject anotherObject;

    public void DoStuff() {
        if (SomeCondition()) anotherObject.SomeInt += 1;
    }
}

ここで、次の のコレクションがあるとしますSomeObject

IList<SomeObject> allObjects = new List<SomeObject>(1000);
// ... Pretend the list is populated with 1000 SomeObjects here

DoStuff()次のように、それぞれを呼び出すとしましょう。

foreach (var @object in allObjects) @object.DoStuff();

これまでのところ、すべて順調です。DoStuff()ここで、オブジェクトが呼び出される順序は重要ではないと仮定しましょう。SomeCondition()おそらく、それは計算コストが高いと仮定します。次のようにすると、マシンの 4 つのコアすべてを利用できます (そして、パフォーマンスが向上する可能性があります)。

Parallel.For(0, 1000, i => allObjects[i].DoStuff());

ここで、変数アクセスの原子性に関する問題を無視して、ループにいる間は、指定されたorSomeObjectの古いバージョンが表示されているかどうかは気にしません。*ただし、ループが完了したら、自分のメイン ワーカー スレッド (つまり、Parallel.For を呼び出したスレッド) は、すべて最新のものを認識します。anotherObjectSomeInt

Parallel.For を使用すると、これが保証されますか (たとえば、ある種のメモリ バリアですか?)。それとも、自分でなんらかの保証をする必要がありますか? または、この保証を行う方法はありませんか?

Parallel.For(...)最後に、直後に同じ方法で再度呼び出した場合、すべてのワーカー スレッドはすべての新しい最新の値で動作するでしょうか?


(*) の実装者DoStuff()は、とにかく処理の順序について仮定を行うのは間違っていますよね?

4

2 に答える 2

1
        var locker = new object();
        var total = 0.0;
        Parallel.For(1, 10000000,
        i => { lock (locker) total += (i + 1); });
        Console.WriteLine("WithLocker" + total);

        var total2 = 0.0;
        Parallel.For(1, 10000000,
        i => total2 += (i + 1));
        Console.WriteLine("WithoutLocker" + total2);
        Console.ReadKey();

        // WithLocker 50000004999999
        // WithoutLocker 28861729333278

私はあなたのために2つの例を作りました。

于 2013-09-07T21:21:00.897 に答える