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();

如果我将 select for found 更改为.ToArray(),那么它工作正常并且我得到计算结果。

任何想法我做错了什么?

4

1 回答 1

4

当您的 PLINQ 查询执行时,“找到的”IEnumerable<T>尚未完全执行。由于默认情况下 LINQ to Objects 使用延迟执行,因此在 PLINQ 查询到达该位置之前,不会创建“Found”的每个元素。

由于 ForAll 方法在内部使用 found 执行,因此它得到了一个未执行的或仅部分枚举的序列。通过在 .ForAll 调用之前添加 .ToArray() (或 ToList - 基本上是强制执行 LINQ to Objects 查询的任何内容),您将强制执行 LINQ to Objects 查询,从而允许 PLINQ 查询正确执行.

于 2010-05-07T15:33:09.980 回答