的IEnumerable的
正确的操作继我以前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);
当你在串联中的项目并分配回给_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
实例之前创建列表。
由于性能损失,列表被有意避免。 AddRange需要大约1秒来连接两个列表,每个列表中有500万个项目,其中Concat在几毫秒内执行相同的操作。你认为可能有任何解决方法来使用Concat而不是AddRange? – Hamed 2015-02-18 07:10:59
@Hamed:性能测试是比较苹果和橘子。 'Concat'方法实际上并没有连接集合,它创建了一个将在迭代时连接集合的查询。 'Concat'调用速度非常快,因为它不会执行实际的工作,稍后迭代结果时会执行此操作。如果你真的意识到串联的集合,你会看到“AddRange”快了大约十倍。 – Guffa 2015-02-18 08:06:17
我刚刚意识到* Concat *的意义。当你想迭代时,它需要所有连接的引用都是活着的,这在我的场景中是不可接受的。 – Hamed 2015-02-18 08:12:18
你永远更新是在方法DoJob(),因为您是按值将它传递给函数的构造函数中定义的变量“结果”。一种可能的解决方案是将其初始化为新的List()而不是null。 – 2015-02-17 23:06:08
@AugustoBarreto我也试过ref关键字,它没有工作。初始化由一个*新List()*迫使我使用* AddRange *而不是* Concat *,这在我的应用程序中被认为是一个高性能损失。 – Hamed 2015-02-18 07:12:56