【问题标题】:C# Parallel foreach - System.AggregateException: One or more errors occurred. ---> System.IndexOutOfRangeException [closed]C# Parallel foreach - System.AggregateException:发生一个或多个错误。 ---> System.IndexOutOfRangeException [关闭]
【发布时间】:2012-10-11 19:32:39
【问题描述】:

找到了答案,...代码中的错误是我将数据添加到错误的列表中


我知道这已被问过几次,但我根本无法弄清楚为什么这会出现异常,我是否在某处丢失了锁?

var sendsToday = new List<TSend>();

var threads = _maxNumberOfThreads;
if (threads <= 0)
    threads = 1;

Parallel.ForEach(_subscribers,
    new ParallelOptions { MaxDegreeOfParallelism = threads },
    () => new ContentSendLocalStorage<TSend, TMedium>(_contentServices, _logService),
    (subscriber, loopState, localStorage) =>
    {
        localStorage.LogService.Warning(string.Format("Choosing content for subscriber {0}", subscriber.SubscriberId));
        foreach (var newsletterId in subscriber.SubscribedNewsletterIds)
        {
            localStorage.LogService.Warning(string.Format("Choosing content for newsletter {0}", newsletterId));
            var clicks = StateBag.Get<LookupList>(StateKeys.LookupList).Clicks.Where(c => c.Subscriber.SubscriberId == subscriber.SubscriberId).Select(c => c.Content.ContentId).ToArray();

            foreach (var contentService in _contentServices.Where(contentService => contentService.Contents.Count != 0))
            {
                subscriber.UrlsClicked = contentService.Contents
        .Where(c => clicks.Contains(c.ContentId))
        .GroupBy(g => g.Page.Url)
        .ToDictionary(k => k.Key, v => 1);

                var best = contentService.GetBestForSubscriber(subscriber, new TMedium { MediumId = int.Parse(newsletterId) });
                if (best != null)
        sendsToday.Add(best);
            }
        }

        localStorage.LogService.Warning(string.Format("Done choosing content for subscriber {0}", subscriber.SubscriberId));
        return localStorage;
    },
    finalStorage =>
    {
        lock (ContentSendLock)
        {
            sendsToday.AddRange(finalStorage.SubscriberSends);
        }
    });

我不断收到以下异常:

System.AggregateException: One or more errors occurred. ---> System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at System.Collections.Generic.List`1.Add(T item)
   at WFM.Newsletter.Business.CORE.OptimizationEngine`2.<>c__DisplayClassd.<Start>b__4(Subscriber subscriber, ParallelLoopState loopState, ContentSendLocalStorage`2 localStorage)
   at System.Threading.Tasks.Parallel.<>c__DisplayClass21`2.<ForEachWorker>b__1a(Int32 i, ParallelLoopState state, TLocal local)
   at System.Threading.Tasks.Parallel.<>c__DisplayClassf`1.<ForWorker>b__c()
   at System.Threading.Tasks.Task.InnerInvoke()
   at System.Threading.Tasks.Task.InnerInvokeWithArg(Task childTask)
   at System.Threading.Tasks.Task.<>c__DisplayClass7.<ExecuteSelfReplicating>b__6(Object )
   --- End of inner exception stack trace ---
   at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
   at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
   at System.Threading.Tasks.Parallel.ForWorker[TLocal](Int32 fromInclusive, Int32 toExclusive, ParallelOptions parallelOptions, Action`1 body, Action`2 bodyWithState, Func`4 bodyWithLocal, Func`1 localInit, Action`1 localFinally)
   at System.Threading.Tasks.Parallel.ForEachWorker[TSource,TLocal](TSource[] array, ParallelOptions parallelOptions, Action`1 body, Action`2 bodyWithState, Action`3 bodyWithStateAndIndex, Func`4 bodyWithStateAndLocal, Func`5 bodyWithEverything, Func`1 localInit, Action`1 localFinally)
   at System.Threading.Tasks.Parallel.ForEachWorker[TSource,TLocal](IEnumerable`1 source, ParallelOptions parallelOptions, Action`1 body, Action`2 bodyWithState, Action`3 bodyWithStateAndIndex, Func`4 bodyWithStateAndLocal, Func`5 bodyWithEverything, Func`1 localInit, Action`1 localFinally)
   at System.Threading.Tasks.Parallel.ForEach[TSource,TLocal](IEnumerable`1 source, ParallelOptions parallelOptions, Func`1 localInit, Func`4 body, Action`1 localFinally)
   at WFM.Newsletter.Business.CORE.OptimizationEngine`2.Start()
   at WFM.Newsletter.Business.CORE.OptimizationService.Start(IEnumerable`1 subscribers, IEnumerable`1 newsletters, LookupList lookupList, LocalConfig config, ILogging logService, Int32 maxNumberOfThreads, String subscriberClicksSourceTableName)
---> (Inner Exception #0) System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at System.Collections.Generic.List`1.Add(T item)
   at WFM.Newsletter.Business.CORE.OptimizationEngine`2.<>c__DisplayClassd.<Start>b__4(Subscriber subscriber, ParallelLoopState loopState, ContentSendLocalStorage`2 localStorage)
   at System.Threading.Tasks.Parallel.<>c__DisplayClass21`2.<ForEachWorker>b__1a(Int32 i, ParallelLoopState state, TLocal local)
   at System.Threading.Tasks.Parallel.<>c__DisplayClassf`1.<ForWorker>b__c()
   at System.Threading.Tasks.Task.InnerInvoke()
   at System.Threading.Tasks.Task.InnerInvokeWithArg(Task childTask)
   at System.Threading.Tasks.Task.<>c__DisplayClass7.<ExecuteSelfReplicating>b__6(Object )<---

---> (Inner Exception #1) System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at System.Collections.Generic.List`1.Add(T item)
   at WFM.Newsletter.Business.CORE.OptimizationEngine`2.<>c__DisplayClassd.<Start>b__4(Subscriber subscriber, ParallelLoopState loopState, ContentSendLocalStorage`2 localStorage)
   at System.Threading.Tasks.Parallel.<>c__DisplayClass21`2.<ForEachWorker>b__1a(Int32 i, ParallelLoopState state, TLocal local)
   at System.Threading.Tasks.Parallel.<>c__DisplayClassf`1.<ForWorker>b__c()
   at System.Threading.Tasks.Task.InnerInvoke()
   at System.Threading.Tasks.Task.InnerInvokeWithArg(Task childTask)
   at System.Threading.Tasks.Task.<>c__DisplayClass7.<ExecuteSelfReplicating>b__6(Object )<---

---> (Inner Exception #2) System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at System.Collections.Generic.List`1.Add(T item)
   at WFM.Newsletter.Business.CORE.OptimizationEngine`2.<>c__DisplayClassd.<Start>b__4(Subscriber subscriber, ParallelLoopState loopState, ContentSendLocalStorage`2 localStorage)
   at System.Threading.Tasks.Parallel.<>c__DisplayClass21`2.<ForEachWorker>b__1a(Int32 i, ParallelLoopState state, TLocal local)
   at System.Threading.Tasks.Parallel.<>c__DisplayClassf`1.<ForWorker>b__c()
   at System.Threading.Tasks.Task.InnerInvoke()
   at System.Threading.Tasks.Task.InnerInvokeWithArg(Task childTask)
   at System.Threading.Tasks.Task.<>c__DisplayClass7.<ExecuteSelfReplicating>b__6(Object )<---

【问题讨论】:

    标签: c# multithreading parallel.foreach


    【解决方案1】:

    在您的内部 foreach 中,您将添加到作为 List 的 sendToday。这发生在每个线程上。

    if (best != null)
        sendsToday.Add(best);
    }
    

    不要使用 List,而是尝试使用 System.Collections.Concurrent 实现之一(例如 ConcurrentBag)。它在内部为您处理所有锁定,并且专为线程而设计。

    var sendsToday = new ConcurrentBag<TSend>();
    

    【讨论】:

    • 所以在这种情况下我不需要 finalStorage => ?
    • 没错。由于所有线程都将直接写入集合,因此您不需要在最后进行聚合。
    • 我仍然怀疑它是锁定问题,因为在这种情况下,.Net 正在处理并行分离,然后我有一个 finalStorage 将它们全部合并,你不这么认为吗?只是一个想法。
    • 在你的 foreach 中,你直接添加到 sendToday -> sendToday.Add(best);所以你试图从每个线程中更改 List。
    【解决方案2】:

    找到了答案,我既不需要改变我的逻辑来引入 ConcurrentBag,也没有大容量插入的问题。

    代码中的错误是我将数据添加到错误的列表中,即 sendToday.Add(best);

    相反,我必须将其添加到“本地存储”中,由 .Net 本身在我的最终存储中使用锁来处理。

    所以不是

     if (best != null)
            sendsToday.Add(best);
    

    正确的代码是

    if (best != null)
    localStorage.SubscriberSends.Add(best);  
    

    最终存储最终通过锁定机制合并每个。

    感谢大家的支持!

    【讨论】:

      【解决方案3】:

      由于产生异常的方法是List&lt;T&gt;.Add()我猜这里抛出异常:

      sendsToday.Add(best);
      

      在列表访问权限周围添加lock,看看是否有帮助。

      【讨论】:

        猜你喜欢
        • 2023-04-06
        • 1970-01-01
        • 2018-01-12
        • 2014-12-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-24
        相关资源
        最近更新 更多