WinForms TPL模式/多任务模式UI同步-这是正确的

本文关键字:模式 同步 TPL 多任务 UI WinForms | 更新日期: 2023-09-27 18:02:49

我是TPL(任务并行库)的新手,我想知道以下是否是启动1个或多个任务,整理结果并在数据网格中显示它们的最有效方法。

  1. Search1,Search2与两个独立的数据库对话,但返回相同的结果。
  2. 我禁用按钮并打开旋转器。
  3. 我正在使用单个ContinueWhenAll方法调用来启动任务。
  4. 我在ContinueWhenAll调用中添加了调度程序来更新表单按钮、数据网格和关闭旋转器。
问:我这样做对吗?有没有更好的办法?
问:如何添加取消/异常检查?
问:如果我需要添加进度报告,我该怎么做?

我选择这种方法而不是后台工作器的原因是,这样我就可以并行地而不是顺序地启动每个DB任务。除此之外,我认为使用TPL可能会很有趣。然而,因为我找不到任何具体的例子来说明我在下面做的事情(多个任务),我想把它放在这里得到答案可能会很好,希望能成为其他人的一个例子。

谢谢!

代码:

//  Disable buttons and start the spinner
btnSearch.Enabled = btnClear.Enabled = false;
searchSpinner.Active = searchSpinner.Visible = true;
//  Setup scheduler
TaskScheduler scheduler = TaskScheduler.FromCurrentSynchronizationContext();
//  Start the tasks
Task.Factory.ContinueWhenAll(
  //  Define the search tasks that return List<ImageDocument>
  new [] {  
    Task.Factory.StartNew<List<ImageDocument>>(Search1), 
    Task.Factory.StartNew<List<ImageDocument>>(Search2) 
  }, 
  //  Process the return results
  (taskResults) => {
    //  Create a holding list
    List<ImageDocument> documents = new List<ImageDocument>();
    //  Iterate through the results and add them to the holding list
    foreach (var item in taskResults) {
      documents.AddRange(item.Result);
    }
    //  Assign the document list to the grid
    grid.DataSource = documents;
    //  Re-enable the search buttons
    btnSearch.Enabled = btnClear.Enabled = true;
    //  End the spinner
    searchSpinner.Active = searchSpinner.Visible = false;
  }, 
  CancellationToken.None, 
  TaskContinuationOptions.None, 
  scheduler
);

WinForms TPL模式/多任务模式UI同步-这是正确的

问:我这样做对吗?有没有更好的办法?

是的,这是处理这种情况的好方法。就我个人而言,我会考虑将UI的disable/enable重构为一个单独的方法,但除此之外,这似乎是非常合理的。

问:如何添加取消/异常检查?

你可以传递一个CancellationToken给你的方法,让它们检查它,并在请求取消时抛出。

你会处理异常,你从taskResults中抓取结果。这条线:

  documents.AddRange(item.Result);

如果在操作期间发生异常或取消,异常将被抛出的位置(作为AggregateExceptionOperationCanceledException)。

问:如果我需要添加进度报告-我该怎么做?

最简单的方法是将调度器传递到方法中。一旦你这样做了,你可以用它来调度一个任务,更新UI线程-即:Task.Factory.StartNewTaskScheduler指定。


然而,因为我找不到任何具体的例子来说明我在下面做的事情(多个任务)

仅供参考-我在TPL系列的第18部分中有处理多个任务的示例。

有关最佳实践,请阅读基于任务的异步模式文档。它包括关于取消支持和基于Task的api的进度通知的建议。

您还可以从异步CTP中的async/await关键字中受益;它们大大简化了任务的延续。