なぜParallel.ForEachループは浅いコピーだけを行うのですか?

私は次のコードを持っています:

List> materialCombos;
Parallel.ForEach(materialCombos, combination =>
{
   Material material1 = combination[0];
   Material material2 = combination[1];                                              
   double[] tempValues1 =
        material1.MaterialImages
                 .OrderBy(mi => mi.Time)
                 .Select(mi => Convert.ToDouble(mi.Temperature))
                 .ToArray();
});


public class Material
{
        [Key]
        public int MaterialID { get; set; }

        /// 
        /// Name of the material.
        /// 
        public string Name { get; set; }

       //other accessors here...

        /// 
        /// Collection of apparent temperature images with meta-data for this material.
        /// 
        public virtual ICollection MaterialImages { get; set; }
}

同期foreachループを使用すると、完全に正常に動作します。しかし、上記のようにパラレルバージョンを使用すると、 MaterialImages オブジェクトは常に combination オブジェクトにコピーされるわけではなく、デバッガで表示するとnullですしたがって、匿名関数で例外がスローされます。

これが起こっている理由は何ですか?なぜなら、それがmaterialCombosを反復して各コンビネーションを取得すると、それは浅いコピーなのですから?

0
はい - あなたは正しいタプル/ keyvaluepairコードを改善するでしょう。しかし、これは問題ではありません。デバッガでは、materailCombosオブジェクトには、すべてのメンバーが正しく入力された完璧な組があります。匿名メソッドにデバッグすると、MaterialImagesメンバーはnullになり、2回目または3回目の繰り返しで発生します。
追加された 著者 Seth,
私。 combination オブジェクトの上にマウスを置いて combination [1] .MaterialImages を見ると、nullの可能性があります。最初の反復では起こらないので、私は 'may'と言います。
追加された 著者 Seth,
Material オブジェクトは、Materialテーブルを表すエンティティフレームワークで使用されるモデルオブジェクトです。
追加された 著者 Seth,
MaterialImagesはEFのための仮想です。
追加された 著者 Seth,
@Gabe - あ、多分MaterialImagesがEF経由でまだロードされていないのですか?
追加された 著者 Seth,
MaterialImages はここには表示されない仮想プロパティです。おかしなことに、スレッドセーフではないものがあります。おそらくあなたのコードのどこかに競合状態がありますが、それまでに投稿したコードにはありません。
追加された 著者 Gabe,
リストを反復処理するときに、項目が浅くコピーされることはありません。私はあなたの問題が不完全な入力セットから来ていると推測します。すなわち、1つ以上の組み合わせが0または1の材料を持っています。なぜバリエーションのリストの代わりにタプルやキーの値ペアを使用しないのですか?
追加された 著者 Polity,

2 答え

元の投稿は、EFオブジェクトのコンテキストからオブジェクトを使用しているという事実を省いています。これはスレッドセーフではないので、あなたが望むものを並行して実行することはできません。すべてのオブジェクトを取得し、それらを同時に操作する場合は動作しますが、私はEFの専門家ではありません。

2
追加された

You should probably be using a thread safe collection. Switch your type to a ConcurrentBag> for starters. Also, doesnt look like you are showing what you are doing with the array within the loop (the snippet of code is incomplete)....if you are expecting to access anything you build up within the loop outside of the parralel loop, you will need to make sure that it is also using a thread safe implementation.

あなたがおそらくデバッガで見ているものは、スレッディングによる非決定的な振る舞いです。

0
追加された
私は List > に対してのみ読み込み操作を行います。私はそれを変異させない。
追加された 著者 Seth,
コレクションでは、実際に読み取りアクセスを同期させる必要はありません。 (もちろん、投稿された抜粋の外側のどこかに書き込むことができます)。
追加された 著者 millimoose,
ノートは、読み込み時のみスレッドセーフです。
追加された 著者 Polity,
その不完全なコードスニペットは、私たちが上に見ていない何か他のものが行われているという前提に基づいていました。:)
追加された 著者 Ben Phegan,
ガベの答え+1。
追加された 著者 Ben Phegan,