我正在使用C#Parallel.ForEach来处理超过数千个数据子集。一套需要5到30分钟来处理,具体取决于套装的大小。在带有选项
的计算机中ParallelOptions po = new ParallelOptions();
po.MaxDegreeOfParallelism = Environment.ProcessorCount
我将获得8个并行进程。据我所知,流程在并行任务之间平均分配(例如,第一个任务获得工作号1,9,17等,第二个任务获得2,10,18等);因此,一项任务可以比其他任务更快地完成自己的工作。因为这些数据集花费的时间比其他数据集少。
问题是四个并行任务在24小时内完成工作,但最后一个任务在48小时内完成。有没有机会组织并行性,以便所有并行任务完全平等?这意味着所有并行任务将继续有效,直到完成所有工作?
答案 0 :(得分:4)
由于作业不相等,您无法在处理器之间拆分作业数,并使它们几乎同时完成。我认为你需要的是8个工作线程,它们可以检索下一个工作。你必须使用函数锁来获得下一份工作。
如果我错了,有人会纠正我,但是在我的脑海中......工作线程可以被赋予这样的功能:
public void ProcessJob()
{
for (Job myJob = GetNextJob(); myJob != null; myJob = GetNextJob())
{
// process job
}
}
获得下一份工作的功能如下:
private List<Job> jobs;
private int currentJob = 0;
private Job GetNextJob()
{
lock (jobs)
{
Job job = null;
if (currentJob < jobs.Count)
{
job = jobs[currentJob];
currentJob++;
}
return job;
}
}
答案 1 :(得分:1)
似乎没有现成的解决方案,必须创建它。
我之前的代码是:
var ListOfSets = (from x in Database
group x by x.SetID into z
select new { ID = z.Key}).ToList();
ParallelOptions po = new ParallelOptions();
po.MaxDegreeOfParallelism = Environment.ProcessorCount;
Parallel.ForEach(ListOfSets, po, SingleSet=>
{
AnalyzeSet(SingleSet.ID);
});
为了在所有CPU之间平等分享工作,我仍然使用Parallel
来完成工作,但我使用ForEach
而不是For
和Matt的想法。新代码是:
Parallel.For(0, Environment.ProcessorCount, i=>
{
while(ListOfSets.Count() > 0)
{
double SetID = 0;
lock (ListOfSets)
{
SetID = ListOfSets[0].ID;
ListOfSets.RemoveAt(0);
}
AnalyzeSet(SetID);
}
});
所以,谢谢你的建议。
答案 2 :(得分:1)
其他人建议的一个选择是管理您自己的生产者消费者队列。我想请注意,使用BlockingCollection
可以轻松完成此非常。
BlockingCollection<JobData> queue = new BlockingCollection<JobData>();
//add data to queue; if it can be done quickly, just do it inline.
//If it's expensive, start a new task/thread just to add items to the queue.
foreach (JobData job in data)
queue.Add(job);
queue.CompleteAdding();
for (int i = 0; i < Environment.ProcessorCount; i++)
{
Task.Factory.StartNew(() =>
{
foreach (var job in queue.GetConsumingEnumerable())
{
ProcessJob(job);
}
}, TaskCreationOptions.LongRunning);
}