2015-02-17 43 views
0

正确的操作继我以前question的IEnumerable的<foo>

在多线程程序,不同的线程的每个产生一个很长的结果的列表。当线程完成了它的任务,我想串联不同列表到一个列表。请介意如下:

public struct AccEntry 
{ 
    internal AccEntry(int accumulation) 
     : this() 
    { 
     Accumulation = accumulation; 
    } 
    public int Accumulation { private set; get; } 
} 


internal class Functions 
{ 
    internal Functions(Object lockOnMe, IEnumerable<AccEntry> results) 
    { 
      _lockOnMe = lockOnMe; 
      _results = results; 
      _result = new List<AccEntry>(); 
    } 

    private IEnumerable<AccEntry> _results { set; get; } 
    private List<AccEntry> _result { set; get; } 

    internal void SomeFunction() 
    { 
      /// some time consuming process that builds _result 
      lock(_lockOnMe) 
      { 
       /// The problem is here! _results is always null. 
       if (_results == null) _results = _result; 
       else _results = _results.Concat(_result); 
      } 
    } 
} 

public class ParentClass 
{ 
    public void DoJob() 
    { 
      IEnumerable<AccEntry> results = null; 
      /// initialize and launch multiple threads where each 
      /// has a new instance of Functions, and call SomeFunction. 
    } 
} 

的问题,因为在代码中提到,是_results总是。当线程改变其设置为_result其他线程发现它一次。我也尝试过使用参考关键字功能构造函数为结果,但它没有改变任何东西。

假设以下按预期执行,我想这可能是我错过上述代码的意义呢?!

List<int> listA = new List<int>(); 
List<int> listB = new List<int>(); 
listA.Add(10); 
listB.Add(12); 
IEnumerable<int> listC = null; 
listC = listA; 
listC = listC.Concat(listB); 
+0

你永远更新是在方法DoJob(),因为您是按值将它传递给函数的构造函数中定义的变量“结果”。一种可能的解决方案是将其初始化为新的List()而不是null。 – 2015-02-17 23:06:08

+0

@AugustoBarreto我也试过ref关键字,它没有工作。初始化由一个*新List()*迫使我使用* AddRange *而不是* Concat *,这在我的应用程序中被认为是一个高性能损失。 – Hamed 2015-02-18 07:12:56

回答

1

当你在串联中的项目并分配回给_results变量,将替换您分配给该变量的初始值。这个新的物品集合将在这个实例中是本地的。

而不是使用IEnumerable<>,你必须更换以更新它,使用List<>,你可以在地方项目添加到:

internal class Functions 
{ 
    internal Functions(Object lockOnMe, List<AccEntry> results) 
    { 
      _lockOnMe = lockOnMe; 
      _results = results; 
      _result = new List<AccEntry>(); 
    } 

    private object _lockOnMe; 
    private List<AccEntry> _results; 
    private List<AccEntry> _result; 

    internal void SomeFunction() 
    { 
      /// some time consuming process that builds _result 
      lock(_lockOnMe) 
      { 
       _results.AddRange(_result); 
      } 
    } 
} 

只要确保创建Functions实例之前创建列表。

+0

由于性能损失,列表被有意避免。 AddRange需要大约1秒来连接两个列表,每个列表中有500万个项目,其中Concat在几毫秒内执行相同的操作。你认为可能有任何解决方法来使用Concat而不是AddRange? – Hamed 2015-02-18 07:10:59

+0

@Hamed:性能测试是比较苹果和橘子。 'Concat'方法实际上并没有连接集合,它创建了一个将在迭代时连接集合的查询。 'Concat'调用速度非常快,因为它不会执行实际的工作,稍后迭代结果时会执行此操作。如果你真的意识到串联的集合,你会看到“AddRange”快了大约十倍。 – Guffa 2015-02-18 08:06:17

+0

我刚刚意识到* Concat *的意义。当你想迭代时,它需要所有连接的引用都是活着的,这在我的场景中是不可接受的。 – Hamed 2015-02-18 08:12:18

相关问题