Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/269.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# 具有模划分的并行Foreach_C#_Parallel.foreach - Fatal编程技术网

C# 具有模划分的并行Foreach

C# 具有模划分的并行Foreach,c#,parallel.foreach,C#,Parallel.foreach,使用Parallel.Foreach()时,对于使用4个线程的100个项目,它会将列表分成4个项目块(0-24,25-49,50-74,75-99),这意味着项目0、25、50和75是并行处理的 是否有可能以模的方式对项目进行分区,以首先处理索引较低的项目?比如: Thread 1: 0, 5, 9,.. Thread 2: 1, 6, 10,... Thread 3: 2, 7, 11,... Thread 4: 3, 8, 12,... 这种分区方法称为循环(Round-Robin)或条带

使用
Parallel.Foreach()
时,对于使用4个线程的100个项目,它会将列表分成4个项目块(0-24,25-49,50-74,75-99),这意味着项目0、25、50和75是并行处理的

是否有可能以模的方式对项目进行分区,以首先处理索引较低的项目?比如:

Thread 1: 0, 5, 9,..
Thread 2: 1, 6, 10,...
Thread 3: 2, 7, 11,...
Thread 4: 3, 8, 12,...

这种分区方法称为循环(Round-Robin)或条带化。将它与
Parallel.ForEach()
一起使用的主要挑战是
ForEach()
需要分区器支持动态分区,这在这种类型的分区中是不可能的,因为分区数必须在执行循环之前固定

实现此类分区的一种方法是创建一个从
System.Collections.Concurrent.Partitioner
派生的自定义类,并使用
ParallelQuery.ForAll()
方法,该方法不具备动态分区支持要求。对于大多数应用程序,这应该相当于使用
ForEach()

下面是一个自定义
分区器的示例和一个基本实现。
Partitioner
将生成与并行度相同数量的分区

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;

namespace RoundRobinPartitioning
{
    public class RoundRobinPartitioner<TSource> : Partitioner<TSource>
    {
        private readonly IList<TSource> _source;

        public RoundRobinPartitioner(IList<TSource> source)
        {
            _source = source;
        }

        public override bool SupportsDynamicPartitions { get { return false; } }

        public override IList<IEnumerator<TSource>> GetPartitions(int partitionCount)
        {
            var enumerators = new List<IEnumerator<TSource>>(partitionCount);

            for (int i = 0; i < partitionCount; i++)
            {
                enumerators.Add(GetEnumerator(i, partitionCount));
            }

            return enumerators;
        }

        private IEnumerator<TSource> GetEnumerator(
            int partition,
            int partitionCount)
        {
            int position = partition;
            TSource value;

            while (position < _source.Count)
            {
                value = _source[position];
                position += partitionCount;
                yield return value;
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var values = Enumerable.Range(0, 100).ToList();

            var partitioner = new RoundRobinPartitioner<int>(values);

            partitioner.AsParallel()
                .WithDegreeOfParallelism(4)
                .ForAll(value =>
                {
                    // Perform work here
                });
        }
    }
}
使用系统;
使用System.Collections.Concurrent;
使用System.Collections.Generic;
使用System.Linq;
命名空间RoundRobinPartitioning
{
公共类RoundRobinPartitioner:Partitioner
{
私有只读IList_源;
公共RoundRobinPartitioner(IList来源)
{
_来源=来源;
}
公共覆盖布尔支持动态分区{get{return false;}}
公共覆盖IList GetPartitions(int partitionCount)
{
变量枚举数=新列表(分区计数);
对于(int i=0;i
{
//在这里工作
});
}
}
}

为什么需要这样做?请尝试指定分区器:并将列表分块,然后将每个分块发送到parallel foreach?不要这样做:每个CPU核心都有自己的缓存,缓存线为16字节;所以缓存开始相互感觉(锁定、检查锁定、重新加载等)。通常的规则是尽可能地将不同线程(任务)的数据放在一起。你怎么会认为它首先执行0、25、50和75?这正是我在问题中所问的。我忘了提的是:我想休息()。对于ForAll(),这可能吗?我可以设置一个中断标志,该标志作为要执行的操作中的第一个被检查,但我仍然必须遍历所有项。