Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Parallel.ForEach缺少项_C#_.net_Parallel.foreach - Fatal编程技术网

C# Parallel.ForEach缺少项

C# Parallel.ForEach缺少项,c#,.net,parallel.foreach,C#,.net,Parallel.foreach,我有以下代码: HttpContext httpContext = HttpContext.Current; RequestContext currentContext = RequestContextManager.CurrentContext; ILifetimeScope currentSessionScope = PlatformContext.LifeTimeScope; ConcurrentQueue<Exception> exceptions = new Concur

我有以下代码:

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);
HttpContext-HttpContext=HttpContext.Current;
RequestContext currentContext=RequestContextManager.currentContext;
ILifetimeScope currentSessionScope=平台上下文.LifeTimeScope;
ConcurrentQueue exceptions=新建ConcurrentQueue();
ConcurrentBag forEachResult=新ConcurrentBag();
ConcurrentBag testForEachPassResult=新ConcurrentBag();
ParallelLoopResult loopResult=Parallel.ForEach(应用程序,()=>
{
HttpContext.Current=HttpContext;
RequestContextManager.SetCustomCurrentContext(currentContext);
PlatformContext.LifeTimeScope=当前会话范围;
返回新的并行计算bj();
},(应用程序,pls,本地对象)=>
{
尝试
{
//一些代码
}
捕获(例外e)
{
例外情况。排队(e);
}
testForEachPassResult.Add(localObj);
返回localObj;
},forEachResult.Add);
其中
applications.Count=3
。执行上述代码后,我得到了
forEachResult.Count=2
testForEachPassResult.Count=3

为什么forEachResult集合不包含所有元素? 没有异常,
ParallelLoopResult.IsCompleted=true

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

  • Item01->Thread.CurrentThread.ManagedThreadId为14
  • Item02->Thread.CurrentThread.ManagedThreadId为10
  • Item03->Thread.CurrentThread.ManagedThreadId为14
  • 试一试

    很可能在添加元素时,您没有列表的最新状态。请记住,列表可以同时从另一个线程添加另一个元素。因此,当它被更改时,您可以将新项添加到旧版本的testForEachPassResult中

    如果您锁定列表,所有其他线程将等待列表解锁。

    我认为您使用的方式错误

    您正在使用具有本地状态的重载。这个局部状态对于分区/线程是唯一的,但不是每个迭代都有唯一的局部状态

    考虑将输入列表划分为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);
            }
        });
    
    Parallel.ForEach(
    应用,
    ()=>新列表(),
    (应用程序,pls,本地OBJ)=>
    {
    //做点什么
    var obj=新的并行计算bj{/*迭代的数据*/};
    localObj.Add(obj);
    返回localObj;
    },
    localObj=>
    {
    foreach(localObj中的var结果)
    {
    forEachResult.Add(结果);
    }
    });
    

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

    有3种方法,其中两种已经提到过

    (1) 每个循环创建一个集合并将其结果添加到此任务结果集合。完成后,将合并所有任务结果。我将使用它作为默认值,因为if避免了锁争用

    (2) 在所有任务之外创建公共集合。所有任务都写入集合,但写入此集合(添加项)必须与锁同步,因为它不是原子的。如果只有100个项目需要处理,但每个项目的处理时间为1秒或更长,我会使用此选项。在这种情况下,锁定时间可以忽略不计

    (3) 在所有任务之外创建一个数组,并为每个任务指定一个区域来写入结果。即使所有任务都写入同一个数组,它们写入的内存位置也不同。因此不需要同步

    示例(3)

    //源必须是数组或IList。
    var source=Enumerable.Range(0,100000).ToArray();
    //对整个源阵列进行分区。
    var rangePartitioner=Partitioner.Create(0,source.Length);
    double[]结果=新的double[source.Length];
    //并行地在分区上循环。
    Parallel.ForEach(rangePartitioner,(range,loopState)=>
    {
    //在没有委托调用的情况下在每个范围元素上循环。
    对于(int i=range.Item1;i

    代码来源:

    这就是我使用System.Collections.Concurrent命名空间的原因。这是线程安全的。非常感谢!但是你能给我解释一下使用localFinally部分的目的吗?我不能在循环体中将项添加到集合中吗?@MateuszPuwałowski localFinally将每个分区的结果合并成一个最终值。以问题为例:您有两个分区,第一个分区包含Item01和Item03,第二个分区包含Item02。这两个本地列表包含处理Item01和Item03的结果以及Item02的结果。localFinally步骤然后将这两个列表合并为一个包含所有三个结果的列表。
    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);
            }
        });
    
    // Source must be array or IList.
    var source = Enumerable.Range(0, 100000).ToArray();
    
    // Partition the entire source array.
    var rangePartitioner = Partitioner.Create(0, source.Length);
    
    double[] results = new double[source.Length];
    
    // Loop over the partitions in parallel.
    Parallel.ForEach(rangePartitioner, (range, loopState) =>
    {
        // Loop over each range element without a delegate invocation.
        for (int i = range.Item1; i < range.Item2; i++)
        {
            results[i] = source[i] * Math.PI;
        }
    });