使用PLINQ AsParallel()挂起应用程序.LINQ没有问题



我是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行(也许可以重新考虑一下该方法,以便在枚举结束时停止递增索引),它就会起作用。

相关内容

最新更新