Howto: Parallel.Foreach esegue molti processi, dopo che ogni processo ha eseguito un nuovo processo (ma uno alla volta)?

Sono sicuro che qualcuno lo sa e sarò molto grato per la risposta. Non ne so molto di delegati e asynch e simili – quindi per favore dammi un esempio generale di come potrei implementare.

Ho un stream di lavoro in cui posso utilizzare Parallel.Foreach per eseguire un metodo per molti file diversi allo stesso tempo (dolce, macinare quel processore) – tuttavia dopo che il metodo termina ho bisogno di eseguire un altro metodo (genera un rapporto sul precedente processo) e questo secondo metodo non può essere eseguito in parallelo.

Non voglio aspettare che tutti i file in Parallel.ForEach finiscano prima di generare report (non è necessario). Ma se avvio il metodo di generazione del report come il primo metodo termina, mi imbatto in problemi. C’è qualche tipo di coda o qualcosa del genere? Dev’esserci un bel modo per farlo, giusto?

Grazie

Penso che cosa voglia dire Jim G:

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

Il secondo metodo dovrebbe essere incatenato come un compito di continuazione .

All’interno del secondo metodo, usa un lock o un mutex per assicurarti che non funzioni in parallelo.

La coordinazione Arbiter.Interleave primitive in Concurrency and Coordination Runtime (CCR) fornisce un modo semplice per ottenere la funzionalità desiderata. in pratica si passa a 3 gruppi di destinatari 1 per attività concorrenti, 1 per attività esclusive (non eseguite in parallelo) e 1 per l’arresto dell’intero processo. Puoi trovare un esempio di come usarlo qui

Un’altra opzione è usare il modello produttore-consumatore. Si dispone di una raccolta di blocco thread-safe in cui si inseriscono i dati finiti, quindi si dispone di un thread che esegue i report che estraggono i dati da tale raccolta.

 //Collection to hold the data the processed files generated var proccesedDataItems = new new BlockingCollection(); //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(); 

Cose del genere si adattano bene al modello di TPL Dataflow: si crea un blocco parallelo che elabora i file e quindi un altro blocco non parallelo che genera il report:

 var processFileBlock = new TransformBlock( file => ProcessFile(file), new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded }); var generateReportBlock = new ActionBlock( result => GenerateReport(result)); processFileBlock.LinkTo(generateReportBlock); foreach (var file in files) processFileBlock.Post(file); 

Se si desidera attendere fino al termine dell’elaborazione, è necessario aggiungere del codice utilizzando Complete() e Completetion .