操作方法:Parallel.Foreach在每个进程运行一个新进程(但一次只有一个进程)后执行多个进程?

时间:2012-09-07 19:01:17

标签: c# task-parallel-library .net-4.5 parallel.foreach

我相信有人知道这一点,我会非常感谢答案。我对代表和异步等都不太了解 - 所以请给我一个如何实现的一般例子。

我有一个工作流程    我可以使用Parallel.Foreach同时为许多不同的文件执行一个方法(甜,研磨处理器) -    但是在该方法结束后我需要运行另一个方法(它生成一个关于前一个过程的报告),       并且第二种方法不能并行运行。

我不想等到Parallel.ForEach中的所有文件在生成报告之前完成(这是不必要的)。但是如果我在第一种方法结束时启动报告生成方法,那么我会遇到问题。有某种队列或什么?有一些很好的方法,对吧?

由于

5 个答案:

答案 0 :(得分:2)

我认为Jim G的意思是:

var lockObj = new object();

Parallel.Foreach(files, file => 
{
    // Processing file
    lock(lockObj)
    {
        // Generate report.
    }
});

答案 1 :(得分:1)

第二种方法应链接为continuation task

在第二种方法中,使用lock或互斥锁以确保它不会并行运行。

答案 2 :(得分:1)

并发和协调运行时(CCR)中的Arbiter.Interleave协调原语提供了一种实现所需功能的简单方法。基本上你传递3个接收器组1用于并发任务,1个用于独占任务(不是并行执行)和1个用于关闭整个过程。您可以找到如何使用它的示例here

答案 3 :(得分:1)

另一种选择是使用生产者 - 消费者模型。您有一个thread safe blocking collection,您将完成的数据放入其中,然后您有一个运行报告的线程从该集合中提取数据。

//Collection to hold the data the processed files generated
var proccesedDataItems = new new BlockingCollection<ResultData>();

//A thread that processes the files
var processReports = new Task(() =>
{
    //Removes items from the collection, if the collection is empty it blocks
    // or if "CompletedAdded" has been called it will reach the "end" of the 
    // collection
    foreach(var processedData in proccesedDataItems.GetConsumingEnumerable())
    {
        BuildReport(processedData);
    }
});
processReports.Start();    

//Generating the data
Parallel.Foreach(files, file => 
{
   var proccesedData = ProcessFile(file)
   proccesedDataItems.Add(processedData);
});

//Let anyone consuming the collection that you can stop waiting for new items.
proccesedDataItems.CompleteAdding();

答案 4 :(得分:1)

这样的事情非常适合TPL Dataflow的模型:您创建一个处理文件的并行块,然后创建另一个生成报告的非并行块:

var processFileBlock = new TransformBlock<File, Result>(
    file => ProcessFile(file),
    new ExecutionDataflowBlockOptions
    {
        MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded
    });

var generateReportBlock = new ActionBlock<Result>(
    result => GenerateReport(result));

processFileBlock.LinkTo(generateReportBlock);

foreach (var file in files)
    processFileBlock.Post(file);

如果您还想等到所有处理完成,则需要使用Complete()Completetion添加一些代码。