2

最近、レポートの累計を計算する必要がありました。各グループについて、行を並べ替えてから、グループ内の前の行に基づいて現在の合計を計算します。あはは!PLINQ の完璧なユース ケースだと思いました。

しかし、コードを書き上げると、奇妙な動作が発生しました。変更していた値は、デバッガーをステップ実行すると変更されたように表示されましたが、アクセスすると常にゼロでした。

サンプルコード:

class Item
{
 public int PortfolioID;
 public int TAAccountID;
 public DateTime TradeDate;
 public decimal Shares;
 public decimal RunningTotal;
}

List<Item> itemList = new List<Item>
{
 new Item
 {
  PortfolioID = 1,
  TAAccountID = 1,
  TradeDate = new DateTime(2010, 5, 1),
  Shares = 5.335m,
 },
 new Item
 {
  PortfolioID = 1,
  TAAccountID = 1,
  TradeDate = new DateTime(2010, 5, 2),
  Shares = -2.335m,
 },
 new Item
 {
  PortfolioID = 2,
  TAAccountID = 1,
  TradeDate = new DateTime(2010, 5, 1),
  Shares = 7.335m,
 },
 new Item
 {
  PortfolioID = 2,
  TAAccountID = 1,
  TradeDate = new DateTime(2010, 5, 2),
  Shares = -3.335m,
 },

};

var found = (from i in itemList
   where i.TAAccountID == 1
   select new Item
   {
    TAAccountID = i.TAAccountID,
    PortfolioID = i.PortfolioID,
    Shares = i.Shares,
    TradeDate = i.TradeDate,
    RunningTotal = 0
   });

found.AsParallel().ForAll(x =>
{
 var prevItems =  found.Where(i => i.PortfolioID == x.PortfolioID
  && i.TAAccountID == x.TAAccountID 
  && i.TradeDate <= x.TradeDate);
 x.RunningTotal = prevItems.Sum(s => s.Shares);
});

foreach (Item i in found)
{
 Console.WriteLine("Running total: {0}", i.RunningTotal);
}

Console.ReadLine();

見つかったの選択を に変更すると、正常に.ToArray()動作し、結果が計算されます。

私が間違っていることは何ですか?

4

1 に答える 1

4

PLINQ クエリが実行されるとき、「見つかった」IEnumerable<T>は完全には実行されていません。LINQ to Objects は既定で遅延実行を使用するため、"Found" の各要素は、PLINQ クエリがその位置に到達するまで作成されません。

ForAll メソッドは内部で find を使用して実行されるため、実行されていない、または部分的にしか列挙されていないシーケンスを取得しています。.ToArray() (または ToList - 基本的に、LINQ to Objects クエリの実行を強制するもの) を .ForAll 呼び出しの前に追加することで、LINQ to Objects クエリの実行を強制し、PLINQ クエリを適切に実行できるようにします。 .

于 2010-05-07T15:33:09.980 に答える