1

此代码仅在调试模式下才能正常工作。我不明白出了什么问题。

我试图修改代码,但没有任何进展。如果第一个参数为真,我想将调用函数 newRow 的结果添加到 hashSet。

foreach (structNumbers sn in numbers)
//Parallel.ForEach(numbers, new ParallelOptions { MaxDegreeOfParallelism = 1 }, (sn) =>
{
    #region                           
    //for (Int32 v = 0; v < 16; v++)
    Parallel.For<Tuple<Boolean, mpz_t, mpz_t>>(0, 16, 
        ()=> { return new Tuple<Boolean, mpz_t, mpz_t>(false, 0, 0); },
        (v, pls, state) =>
    {

        #region
        Interlocked.Increment(ref countChecked);

        //if (newRow(i, j, v, t, index, sn.n, sn.m, out nMin, out mMin) == true)
        //lock(thisLock)
        Tuple<Boolean, mpz_t, mpz_t> res = newRow(i, j, v / 4, v % 4, index, sn.n, sn.m);
        state = new Tuple<bool, mpz_t, mpz_t>(res.Item1, res.Item2, res.Item3);


        return state;

        #endregion

    },
        state => {
            lock (thisLock)
            {
                if (state.Item1 == true)
                {
                    #region  

                    numbersTemp.Add(new structNumbers(state.Item2, state.Item3));
                    //numbersTemp.Add(new structNumbers(nMin, mMin));
                    //Console.WriteLine("bla");
                    #endregion
                }

            }
        }
    );
    #endregion
}
//);
4

2 回答 2

0

如果你想从并行循环聚合多个结果,那么你可以这样做:

object lockObject=new object();
HashSet<TResult> result=new HashSet<TResult>();
Parallel.For(0,16,() => new List<TResult>(),(i,pls,list) => {
    TResult r;
    if(TryGetResult(i,out r)) {
        list.Add(r);
    }
    return list;
},list => {
    lock(lockObject) {
        result.UnionWith(list);
    }
});

但是如果TryGetResult代表大工作(至少它应该足够大以证明并行循环的开销),你可以这样做:

object lockObject=new object();
HashSet<TResult> result=new HashSet<TResult>();
Parallel.For(0,16,i => {
    TResult r;
    if(TryGetResult(i,out r)) {
        lock(lockObject) {
            result.Add(r);
        }
    }
});

或这个:

ConcurrentBag<TResult> bag=new ConcurrentBag<TResult>();
Parallel.For(0,16,i => {
    TResult r;
    if(TryGetResult(i,out r)) {
        bag.Add(r);
    }
});
HashSet<TResult> result=new HashSet<TResult>(bag);

Parallel.For在我看来,类型参数的重载TLocal更适合,当你有标量结果时,没有锁就不能更新:

object lockObject=new object();
BigInteger result=BigInteger.Zero;
Parallel.For(0,16,i => {
    BigInteger r=GetBigInteger(i);
    lock(lockObject) {
        result+=r;
    }
});

在这段代码中,添加两个BigInteger可能是昂贵的操作,并且不能并行完成,因此您最好将代码重写为:

object lockObject=new object();
BigInteger result=BigInteger.Zero;
Parallel.For(0,16,() => BigInteger.Zero,(i,pls,subResult) => {
    return subResult+GetBigInteger(i);
},subResult => {
    lock(lockObject) {
        result+=subResult;
    }
});
于 2015-03-05T15:27:32.460 回答
0

这个版本的Parallel.For()工作方式是它首先将输入分成批次。然后对于每个批次,使用委托初始化本地状态localInit,为批次中的每个数字调用body委托,将最后一个状态传递给它并期望它返回一个新状态,最后调用localFinally最终状态。

由于您忽略了输入的状态body,因此您只将每个批次的最后一项添加到结果中。

PetSerAl 的回答显示了可能的解决方案。可能最合理的开始是最简单的一个lock。如果结果太慢,请寻找更复杂的解决方案,包括使用本地状态的解决方案。

于 2015-03-11T23:00:06.103 回答