C# 选择“相等”;“块”;从并行for循环的IEnumerable范围

C# 选择“相等”;“块”;从并行for循环的IEnumerable范围,c#,multithreading,parallel-processing,C#,Multithreading,Parallel Processing,这是一个由两部分组成的问题 我已通过编程确定了一系列double值: public static void Main(string[] args) { var startRate = 0.0725; var rateStep = 0.001; var maxRate = 0.2; var stepsFromStartToMax = (int)Math.Ceiling((maxRate-startRate)/rateS

这是一个由两部分组成的问题

我已通过编程确定了一系列
double
值:

    public static void Main(string[] args)
    {
        var startRate = 0.0725;
        var rateStep = 0.001;
        var maxRate = 0.2;
        var stepsFromStartToMax = (int)Math.Ceiling((maxRate-startRate)/rateStep);

        var allRateSteps = Enumerable.Range(0, stepsFromStartToMax)
            .Select(i => startRate + (maxRate - startRate) * ((double)i / (stepsFromStartToMax - 1)))
            .ToArray();
        foreach (var i in allRateSteps)
        {
            Console.WriteLine(i); //  this prints the correct values
        }
    }
我想根据处理器计数将此数字列表划分为多个块,我可以从
环境中获得处理器计数。ProcessorCount
(通常为8)。理想情况下,我会以
元组的
列表
结束,其中每个
元组
包含每个块的起始值和结束值:

[(0.725, 0.813), (0.815, 0.955), ...]
1)如何在不知道需要多少元组的情况下,用更少的代码选择内部范围?我想出了一个很长的方法来处理循环,但我希望LINQ能在这里提供帮助:

        var counter = 0;
        var listOne = new List<double>();
        //...
        var listEight = new List<double>();
        foreach (var i in allRateSteps)
        {
            counter++;
            if (counter < allRateSteps.Length/8)
            {
                listOne.Add(i);
            }
            //...
            else if (counter < allRateSteps.Length/1)
            {
                listEight.Add(i);
            }
        }
        // Now that I have lists, I can get their First() and Last() to create tuples
        var tupleList = new List<Tuple<double, double>>{
            new Tuple<double, double>(listOne.First(), listOne.Last()),
            //...
            new Tuple<double, double>(listEight.First(), listEight.Last())
        };
这会打印出来,例如:

...
0.1295 : 00:00:00.4846470 : 5 
0.0825 : 00:00:00.4846720 : 8 
0.1645 : 00:00:00.4844220 : 6 
0.0835 : 00:00:00.4847510 : 8 
...
Thread1需要处理第一个元组中的范围,thread2处理第二个元组中定义的范围,等等。。。其中,
i
由循环中的范围定义。同样,范围元组的数量将取决于处理器的数量。谢谢

我想根据处理器计数将这个数字列表分成几块

对于LINQ
批处理
方法,有以下几种方法

如何在不需要知道需要多少元组的情况下,以更少的代码选择出内部范围

这里有一种处理方法:

var batchRanges = from batch in allRateSteps.Batch(anyNumberGoesHere)
                  let first = batch.First()
                  let last = batch.Last()
                  select Tuple.Create(first, last);

(0.0725, 0.0795275590551181)
(0.0805314960629921, 0.0875590551181102)
(0.0885629921259842, 0.0955905511811024)
...
如何根据我在
tupleList

示例的这一部分没有引用tupleList,因此很难看到所需的行为

Thread1需要处理第一个元组中的范围,thread2处理第二个元组中定义的范围,等等

除非您对某些线程处理某些批处理有严格要求,否则我强烈建议您将工作生成为单个“流”,并使用更高级别的并行抽象,例如

如果您只想成批完成工作,您仍然可以这样做,但不关心在哪个线程上完成工作:

static void Work(IEnumerable<int> ints) {
  var sum = ints.Sum();
  Thread.Sleep(sum);
  Console.WriteLine(ints.Sum());
}

public static void Main (string[] args) {
  var inputs = from i in Enumerable.Range(0, 100)
               select i + i;
  var batches = inputs.Batch(8);
  var tasks = from batch in batches
              select Task.Run(() => Work(batch));
  Task.WaitAll(tasks.ToArray());
}

站点上有许多用于批处理w/LINQ的现有Q&a,但是创建批处理以手动跨核心进行调度可能是不必要的,并且性能不如让一个代理为您处理。为什么不创建自己的
线程
s,并让每个进程都有自己的输入列表?@TaylorWood-您可以在此上下文中动态创建可变数量的线程吗?是的,您可以创建动态大小的线程集合,但为什么不在线程池中使用任务呢?这部分令人困惑:“如何在不知道需要多少元组的情况下,以更少的代码选择出内部范围?“从问题的其余部分来看,你似乎在处理已知的数量和输入。为什么你不知道你需要多少元组?@ScottHannen-我想用LINQ来获取
n
部分中的批,其中
n=Environment.ProcessorCount
。我在我的代码中硬编码了8个处理器的假设,因为我没有办法显示优化的方式(我还不知道),感谢这个伟大的答案。我只是意识到,我实际上不需要将要完成的工作“划分”为某种数据结构,如
listuple
,然后将其提供给并行函数,因为“划分要完成的工作”并将其分布在线程中正是使用这种方法的目的。
static void Work(IEnumerable<int> ints) {
  var sum = ints.Sum();
  Thread.Sleep(sum);
  Console.WriteLine(ints.Sum());
}

public static void Main (string[] args) {
  var inputs = from i in Enumerable.Range(0, 100)
               select i + i;
  var batches = inputs.Batch(8);
  var tasks = from batch in batches
              select Task.Run(() => Work(batch));
  Task.WaitAll(tasks.ToArray());
}
static int Work(IEnumerable<int> ints) {
  Console.WriteLine("Work on thread " + Thread.CurrentThread.ManagedThreadId);
  var sum = ints.Sum();
  Thread.Sleep(sum);
  return sum;
}

public static void Main (string[] args) {
  var inputs = from i in Enumerable.Range(0, 100)
               select i + i;
  var batches = inputs.Batch(8);
  var tasks = from batch in batches
              select Work(batch);
  foreach (var task in tasks.AsParallel()) {
    Console.WriteLine(task);
  }
}

/*
Work on thread 6
Work on thread 4
56
Work on thread 4
184
Work on thread 4
Work on thread 4
312
440
...
*/