c#删除元素后的并行For循环索引异常

时间:2016-12-28 09:39:49

标签: c# multithreading indexoutofboundsexception parallel.foreach

在我的算法中,我要做的是跟随。

while (R.Count > 0)
{
    //R is also  List<string>()   
    var N = new List<string>();
    var first = R[0];
    N.Add(first);
    R.Remove(first);
    //below commented code runs just fine but it takes a lot of time that is why i need to do multithreading to make it faster
    //for (int i = R.Count - 1; i >= 0; i--)
    //{
    //    if (hamming(first, R[i]))
    //    {   //hamming is a function just compare two strings and returns true or false.
    //        N.Add(R[i]);
    //        R.RemoveAt(i);
    //    }
    //}

    //Below is code of my attempt of multithreading the loop. I have tried it with foreach loop as well and it gives same error 'index out of range or argument exception'

    //ATTEMPT 1 :-
    Parallel.For(0,R.Count, i =>
    {

        if (hamming(first, R[i]))
        {
            N.Add(R[i]);
            R.RemoveAt(i);
        }
    });
    //ATTEMPT 2 :-
    Parallel.For(0,R.Count, i =>
    {

        if (hamming(first, R[i]))
        {
            N.Add(R[i]);
            R[i]="";
        }
    });
    var K = R.Where(a => a == "").ToList();
    var nc = cou - N.Count;
    //the value of 'K.Count' and 'nc' should be same here but I have checked in debugger its not the same.

    N_Total.Add(N);//this is just a List<List<string>>

}

“守则”非常自我解释,但我仍会在此进一步阐述。

基本上我需要运行这个算法并比较代码中显示的值,如果汉明返回true,我必须将该值添加到&#39; N&#39;并且从&#39; R&#39;中删除它,我必须删除它,因为当下一次外部while循环运行List&#39; R&#39;应该更小,只有那些值应该存在于R中,这不能满足前一轮循环中的汉明条件。

如果有人需要了解更多内容,我可以进一步详细说明。

我想要的是以多线程方式实现此目标,并且没有index out of rangeArgument exceptions的例外情况。

提前多多感谢。

2 个答案:

答案 0 :(得分:2)

首先List<string>不是ThreadSafe,这意味着它根本不应该用于并行操作。

请尝试:ConcurrentBag<string>

ConcurentBag存在于System.Collections.Concurrent命名空间中,其中包含更多线程安全集合。

另一件事是:

您希望在执行任何操作之前确定该索引是否存在。

ConcurentBag可能有一些限制,也许值得检查该命名空间中的其他集合:System.Collections.Concurrent,因为它们是ThreadSafe

https://msdn.microsoft.com/en-us/library/system.collections.concurrent.aspx

答案 1 :(得分:1)

Parallel.Foreach上使用R。 Parallel.Foreach会将您的列表拆分为较小的块并开始处理它们。所以来自不同线程的索引不会相互冲突。

对于N,您将使用ConcurrentBag代替List,因为其线程安全。这意味着当两个线程碰巧将项目添加到你的包中时,不会发生奇怪的事情。

如果您删除Parallel内的项目,您应该通知所有线程,这些新的更改将很难(并且非常难看)实现。

List<string> R = new List<string>();


while (R.Count > 0)
{
    var removing = new ConcurrentBag<long>();

    var N = new ConcurrentBag<string>();
    var first = R[0];
    N.Add(first);
    R.Remove(first);

    Parallel.ForEach(R, (item, state, index) =>
    {
        if(hamming(first, item))
        {
            N.Add(item);

            R[(int)index] = null; // mark as null and ignore. 
                                  // this is not thread safe for versioning of list but doesn't matter.
                                  // for R ConcurrentBag can be used too but it doesn't change results after all.
        }
    });

    // now we are safe to reorganize our collection.
    R = R.Where(str => str != null).ToList(); // parallel execution doesn't help. see comments below. 
                                              // for very large collection this will finish in few milliseconds.

    // get other stuff...
}