我是LINQ和PLINQ的新手,我正在构建一个测试它们的项目。
存根:
class Stub
{
private Boolean mytf;
public Stub()
{
Random generator = new Random();
if (generator.NextDouble() < 0.5)
{
mytf = false;
}
else mytf = true;
}
public Boolean tf
{
get
{
return mytf;
}
}
}
StubCollection:
class StubCollection : IEnumerable
{
Stub[] stubs;
public StubCollection(int n)
{
stubs = new Stub[n];
for (int i = 0; i < n; i++)
{
stubs[i] = new Stub();
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return new StubIterator(this);
}
public class StubIterator : IEnumerator
{
private StubCollection sc;
private int index = -1;
public StubIterator(StubCollection _sc)
{
sc = _sc;
}
public bool MoveNext()
{
index++;
if (index < sc.stubs.Length)
{
return true;
}
else
{
index = -1;
return false;
}
}
public object Current
{
get
{
if (index <= -1)
{
throw new InvalidOperationException();
}
return sc.stubs[index];
}
}
public void Reset()
{
index = -1;
}
}
}
然后我有一些方法来迭代stubcollection并计算布尔值设置为true的存根数:
的foreach:
Stopwatch sw = new Stopwatch();
Int32 n = 0;
sw.Start();
foreach (Stub s in sc)
if (s.tf) n++;
sw.Stop();
MessageBox.Show("n:" + n.ToString() + " timer:" + sw.ElapsedMilliseconds.ToString());
它有效
LINQ:
Stopwatch sw = new Stopwatch();
Int32 n = 0;
sw.Start();
var trueStubs = from Stub s in sc
where s.tf
select s;
n = trueStubs.Count();
sw.Stop();
MessageBox.Show("n:" + n.ToString() + " timer:" + sw.ElapsedMilliseconds.ToString());
它有效(比foreach慢一点)
PLINQ:
Stopwatch sw = new Stopwatch();
Int32 n = 0;
sw.Start();
var trueStubs = from Stub s in sc.AsParallel()
where s.tf
select s;
n = trueStubs.Count();
sw.Stop();
MessageBox.Show("n:" + n.ToString() + " timer:" + sw.ElapsedMilliseconds.ToString());
100%CPU,无结果
为什么呢?唯一的区别是AsParallel()
答案 0 :(得分:6)
问题出在您的IEnumerator实现中:
public bool MoveNext()
{
index++;
if (index < sc.stubs.Length)
{
return true;
}
else
{
index = -1;
return false;
}
}
我不确定为什么PLINQ会这样做,但是即使到达集合的末尾,也会多次调用MoveNext。问题是您的实现存在缺陷:在到达集合结束后再次调用MoveNext时,索引将重置为-1,因此枚举将重新开始。这就是为什么你陷入无休止的循环。只需删除index = -1
行(并且可能会稍微重新考虑该方法以在达到枚举结束时停止递增索引)并且它将起作用。