在每个foreach()内部生成新线程,但在完成之前不要返回

时间:2017-09-15 16:18:10

标签: c# multithreading

我有一个foreach()循环播放15个报告,并为每个报告生成一个PDF。 PDF生成过程很慢(每个3秒)。但是如果我可以与线程同时生成它们,那么所有15个都可以在4-5秒内完成。一个限制是在生成所有pdf之前,函数不能返回。另外,15个并发工作线程是否会导致dotnet / windows出现问题或不稳定?

这是我的伪代码:

private void makePDFs(string path) {
  string[] folders = Directory.GetDirectories(path);

  foreach(string folderPath in folders) {
     generatePDF(...);   
   }

   // DO NOT RETURN UNTIL ALL PDFs HAVE BEEN GENERATED
 }
}

实现这一目标的最简单方法是什么?

3 个答案:

答案 0 :(得分:4)

最直接的方法是使用Parallel.ForEach

private void makePDFs(string path)
{
    string[] folders = Directory.GetDirectories(path);

    Parallel.ForEach(folders, (folderPath)  => 
      {
          generatePDF(folderPath);   
      };

    //WILL NOT RETURN UNTIL ALL PDFs HAVE BEEN GENERATED
}

这样您就可以避免创建,跟踪和等待每个单独的任务; TPL为你做了一切。

答案 1 :(得分:2)

您需要获取任务列表,然后使用Task.WhenAll等待完成

var tasks = folders.Select(folder => Task.Run(() => generatePDF(...)));
await Task.WhenAll(tasks);

如果您不能或不想使用async/await,可以使用:

Task.WaitAll(tasks);

它将阻止当前线程,直到完成所有任务。所以如果可以,我建议使用第一种方法。

您还可以使用Parallel C#类:

并行运行PDF生成
Parallel.ForEach(folders, folder => generatePDF(...));

请参阅this answer,选择哪种方法最适合您的问题。

答案 2 :(得分:0)

.NET有一个方便的方法:Task.WhenAll(IEnumerable<Task>) 在继续之前,它将等待IEnumerable中的所有任务完成。这是async方法,因此您需要await

var tasks = new List<Task>();
foreach(string folderPath in folders) {
    tasks.Add(Task.Run(() => generatePdf()));
}
await Task.WhenAll(tasks);