这是一个由两部分组成的问题。
我已经以编程方式确定了一系列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
}
}
我想根据处理器数量将这个数字列表分成块,我可以从Environment.ProcessorCount
(通常是8)获得。理想情况下,我最终会得到像{{1}这样的东西} List
,其中每个Tuples
包含每个块的起始值和结束值:
Tuple
1)如何在较少的代码中选择内部范围,而不必知道我需要多少元组?我已经想出了一个很长的方法来做这个循环,但我希望LINQ可以在这里提供帮助:
[(0.725, 0.813), (0.815, 0.955), ...]
一旦我有了这个新的范围元组列表,我想将这些作为并行循环的基础,在某些条件下写入 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())
};
。我不知道如何将这些代码放入我的循环中......
我已经将这段代码用于多个线程,但 2)如何根据ConcurrentDictionary
中定义的范围在所有处理器之间均匀分配工作:
tupleList
这打印出来,例如:
var maxRateObj = new ConcurrentDictionary<string, double>();
var startTime = DateTime.Now;
Parallel.For(0,
stepsFromStartToMax,
new ParallelOptions
{
MaxDegreeOfParallelism = Environment.ProcessorCount
},
x =>
{
var i = (x * rateStep) + startRate;
Console.WriteLine("{0} : {1} : {2} ",
i,
DateTime.Now - startTime,
Thread.CurrentThread.ManagedThreadId);
if (!maxRateObj.Any())
{
maxRateObj["highestRateSoFar"] = i;
}
else {
if (i > maxRateObj["highestRateSoFar"])
{
maxRateObj["highestRateSoFar"] = i;
}
}
});
Thread1需要处理第一个元组中的范围,thread2处理第二个元组中定义的范围等,其中...
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
...
由循环中的范围定义。同样,范围元组的数量将取决于处理器的数量。感谢。
答案 0 :(得分:1)
我想根据处理器数量将这个数字列表分成几个块
LINQ Batch
方法有many possible implementations。
如何在较少的代码中选择内部范围,而不必知道我需要多少元组?
这是处理这个问题的一种方法:
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处理第二个元组中定义的范围等...
除非您对某些线程处理某些批次有一些硬性要求,否则我强烈建议将您的工作生成为单个“流”,并使用更高级别的抽象来实现并行化。 PLINQ
如果你只是想分批工作,你仍然可以这样做但不关心正在进行的工作的哪个线程:
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());
}
默认TaskScheduler
正在为您在幕后协调工作,并且它可能胜过手动推出您自己的线程方案。
还要考虑这样的事情:
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
...
*/