c# - Parallel.ForEach 缺少的项目

标签 c# .net parallel.foreach

我有以下代码:

HttpContext httpContext = HttpContext.Current;
RequestContext currentContext = RequestContextManager.CurrentContext;
ILifetimeScope currentSessionScope = PlatformContext.LifeTimeScope;

ConcurrentQueue<Exception> exceptions = new ConcurrentQueue<Exception>();
ConcurrentBag<ParallelCalculateObj> forEachResult = new ConcurrentBag<ParallelCalculateObj>();
ConcurrentBag<ParallelCalculateObj> testForEachPassResult = new ConcurrentBag<ParallelCalculateObj>();

ParallelLoopResult loopResult = Parallel.ForEach(applications, () =>
{
    HttpContext.Current = httpContext;
    RequestContextManager.SetCustomCurrentContext(currentContext);
    PlatformContext.LifeTimeScope = currentSessionScope;
    return new ParallelCalculateObj();
}, (application, pls, localObj) =>
{
    try
    {
        // some code
    }
    catch (Exception e)
    {
        exceptions.Enqueue(e);
    }
    testForEachPassResult.Add(localObj);
    return localObj;
}, forEachResult.Add);

其中 applications.Count = 3。执行上面的代码后,我得到了 forEachResult.Count = 2testForEachPassResult.Count = 3

为什么forEachResult 集合不包含所有的元素? 也不异常(exception),ParallelLoopResult.IsCompleted = true

可能有助于解决我的问题的一件事是这三个项目在两个线程下运行:

  1. Item01 -> Thread.CurrentThread.ManagedThreadId 为 14
  2. Item02 -> Thread.CurrentThread.ManagedThreadId 为 10
  3. Item03 -> Thread.CurrentThread.ManagedThreadId 为 14

最佳答案

我认为您正在使用 Parallel.ForEach以错误的方式。

您正在使用具有本地状态的重载。此本地状态对于分区/线程是唯一的,但并非每次迭代都具有唯一的本地状态。

考虑将输入列表分成N 个分区。然后有 N 个本地状态。作为最后一步,您将那些 N 个局部状态组合成您的最终值。通常 N 将小于列表中的项目数,除非您使用更具体的重载之一,否则 TPL 将确定列表的分区方式。

由于您显然想用每次迭代的结果填充某个列表,因此您的本地状态也应该是一个列表,其中包含该特定分区的每次迭代的结果。对于最后的操作,您将所有列表合并为一个列表:

Parallel.ForEach(
    applications,
    () => new List<ParallelCalculateObj>(),
    (application, pls, localObj) =>
    {
        // do something
        var obj = new ParallelCalculateObj { /* data of the iteration */ };
        localObj.Add(obj);
        return localObj;
    },
    localObj =>
    {
        foreach (var result in localObj)
        {
            forEachResult.Add(result);
        }
    });

请注意,如果您这样做,则 forEachResult 中值的顺序将与 applications 中的项目顺序不一致。如果需要,则必须使用 ParallelLoopState 类的索引。

关于c# - Parallel.ForEach 缺少的项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24907606/

相关文章:

c# - EF 的 ObjectContext.ApplyCurrentValues 等效项是什么

.net - TweetSharp 获取关注者数量

c# - 如何在 wpf 中使两个段落 block 在同一级别上,在级别上,保持一个 block 左对齐,另一个右对齐?

c# - 如何指定Parallel.ForEach中执行的并行任务数?

没有 IIS 的 c# rest webservice

c# - 如何安全地重定向到引用页面?

c# - PropertyGrid 没有注意到代码中的属性更改?

c# - HttpRequest 与 HttpWebRequest

c# - 对 ConcurrentDictionary 的线程安全更改

powershell - 当传递给invoke-command时,Powershell 7 ForEach-Object Parallel会中断自动变量