【问题标题】:c# Parallel For Loop index exceptions after removing the elementc# Parallel For Loop 删除元素后的索引异常
【发布时间】:2017-05-12 13:43:28
【问题描述】:

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

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>>

}

代码很容易解释,但我仍然会在这里进一步详细说明。

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

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

我想要的是以某种多线程方式实现这一目标,并且没有index out of range 或Argument exceptions 的例外。

非常感谢。

【问题讨论】:

    标签: c# multithreading indexoutofboundsexception parallel.foreach


    【解决方案1】:

    首先List&lt;string&gt; 不是ThreadSafe,这意味着它根本不应该在并行操作中使用。

    试试:ConcurrentBag&lt;string&gt;。

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


    还有一点是:

    您想在对它进行任何操作之前确保该索引是否存在。


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

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

    【讨论】:

    • 我尝试了并发队列,但它只从开头删除项目(如果匹配)所以这对我不起作用,因为我是并行的,所以我必须删除该循环正在访问的任何随机项目时间。
    • 如何从中删除项目?在您的情况下,您想使用 TryTake 方法,我假设返回(将其添加到另一个集合)并从源集合中删除对象。
    【解决方案2】:

    在R 上使用Parallel.Foreach。 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...
    }
    

    【讨论】:

    • ConcurrentBag 'N' 没有任何 'Add' 的扩展方法,我该如何添加项目呢?
    • 仔细检查您的代码。您是否将using System.Collections.Concurrent; 放在代码顶部? @touseef
    • 如果发现R = R.AsParallel().Where(str =&gt; str != null).ToList(); 比R = R.Where(str =&gt; str != null).ToList(); 更高效,我会非常感到惊讶
    • @touseef 请注意,hamming 方法也有其自身的性能影响。你应该详细说明你的列表有多大以及hamming 是如何实现的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-16
    • 1970-01-01
    • 2021-11-24
    • 2022-12-01
    • 2017-02-18
    • 1970-01-01
    相关资源
    最近更新 更多