我是LINQ和PLINQ的新手,我正在构建一个项目来测试它们。
Stub:
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,并计算有多少stub的布尔值设置为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()
问题出在您的IEnumerator实现中:
public bool MoveNext()
{
index++;
if (index < sc.stubs.Length)
{
return true;
}
else
{
index = -1;
return false;
}
}
我不太清楚PLINQ为什么要这样做,但MoveNext会被调用多次,即使在到达集合的末尾时也是如此。问题是您的实现存在缺陷:当到达集合末尾后再次调用MoveNext时,索引将重置为-1,因此枚举将重新开始。这就是你陷入无休止循环的原因。只需删除index = -1
行(也许可以重新考虑一下该方法,以便在枚举结束时停止递增索引),它就会起作用。