任务并行库 - 如何立即返回但具有并行步骤

时间:2012-04-16 19:04:02

标签: c# parallel-processing task-parallel-library

我有以下工作流需要以非阻塞并行处理方式进行。我希望方法DoStuff()能够立即返回,所以我使用的是Task Parallel Libary

DoStuff():
  Do some setup
  Parse an Excel file

  then for each row
   Fill Template with parsed values
   Convert filled template to Pdf
   Convert pdf to Tiff

  when all row processing has completed Create Summary Text File

  when summary text file has completed, Finalize

由于我想立即返回,我在“完成所有行处理”步骤时磕磕绊绊了一下。以下大致是我应该做的事情吗?

public Task<ProcessingResult> DoStuff() {
    return new Task<SetupResult>(SetUp)
        .ContinueWith(ParseExcel, TaskContinuationOptions.OnlyOnRanToCompletion)
        .ContinueWith(excelProcessing => {
            var templateProcessing = excelProcessing.Result.RowParsing
                .Select(template =>
                  new Task<TemplateFillingResult>(()=>FillTemplate)
                       .ContinueWith(ConvertToPdf, TaskContinuationOptions.OnlyOnRanToCompletion)
                       .ContinueWith(ConvertToTiff, TaskContinuationOptions.OnlyOnRanToCompletion)
                ).ToArray()

            //-------------------------------------------------------------
            // This is the part that seems wierd
            //-------------------------------------------------------------
            Task.Factory.ContinueWhenAll(templateTasks, t=> { }).Wait();
            return new TemplatesProcessingResult(templateProcessing);
        }, TaskContinuationOptions.OnlyOnRanToCompletion)
        .ContinueWith(CreateSummaryFile, TaskContinuationOptions.OnlyOnRanToCompletion)
        .ContinueWith(FinalizeProcessing, TaskContinuationOptions.OnlyOnRanToCompletion);

1 个答案:

答案 0 :(得分:6)

我认为你感到困惑,因为你试图将所有这些组件连接起来作为原始事件的延续。如果没有令人信服的理由让所有这些调用延续,那么这一切都可以通过一个后台线程(任务)完成。

var task = Task.Factory.StartNew(() =>
   {
        // setup
        // var stuff = ParseFile()

        // Executes elements in parallel and blocks this thread until all have completed, else bubbles the exception up
        var transformations = excelProcessing.Result.RowParsing.AsParallel().Select(x =>
           {
                FillTemplate(x);
           }).ToArray();

        // create summary text file

        // Finalize

        return processingResult;
   });

基本上,你可以在一个线程中完成所有这些,而不必担心它。将所有这些步骤标记为延续对于您需要执行的操作非常复杂。

然后你的调用代码可以简单地阻止那个人的Result属性来获得异步调用的结果:

  try
  {
      var result = task.Result;
  }
  catch(AggregateException e)
  {
      e.Flatten().Handle(ex => 
        {
             // Do Stuff, return true to indicate handled
        });
  }

然而,您需要认识到的一件事是例外。如果这将是一个火灾和忘记任务,那么如果你有一个例外,它会一直冒泡并可能​​会杀死你的进程。