2

我有以下需要以非阻塞并行处理方式发生的工作流程。我希望该方法DoStuff()立即返回,所以我正在使用任务并行库

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);
4

1 回答 1

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
        });
  }

但是,您需要了解的一件事是例外情况。如果这将是一项“一劳永逸”的任务,那么如果您有异常,它将一直冒泡并可能​​会杀死您的进程。

于 2012-04-16T19:14:09.953 回答