TPL数据流块在UI线程上运行

4
我正在构建一个数据流管道来进行各种处理(主要是I/O,但也有一些CPU处理),这是一个自然发生的流程。目前的流程基本模式如下:
  1. 从文件加载数据
  2. 使用变换块解析记录
  3. 通过REST序列化和上传对象到服务器
这个处理管道可以自动启动,也可以通过GUI启动。对于从GUI启动的情况,我想向最终用户提供进度消息。如果我在步骤1和2之间添加一个BufferBlock,在步骤3后再添加一个ActionBlock,并将它们的选项设置为在与UI相同的线程上运行,那么其他块是否仍然会使用自己的线程池离开UI运行?
我看了这篇MSDN文章:http://msdn.microsoft.com/en-us/library/hh228605(v=vs.110).aspx,但它对这种行为不是很清楚。我能否从管道中触发一个可以在UI线程上运行的事件来实现这个?
编辑:管道将从UI上的BackgroundWorker对象启动,而不是直接从UI线程启动。

你是否正在使用 DataflowBlockOptions.TaskScheduler 来使其在 UI 线程上运行?提供一段代码会更有帮助。 - noseratio - open to work
@Noseratio 这更多是一个理论问题。我仍在计划这个功能。目前它没有报告进度。使用 DataflowBlockOptions.TaskScheduler 是我要告诉那些特定的块在 UI 线程上运行的方法。 - JNYRanger
1
我会使用 Progress<T> 模式来实现,而不是使用 UI 线程的 TaskScheduler。 - noseratio - open to work
@Noseratio 我实际上应该更明确一点,我想使用的不是直接使用 UI 线程,而是通过 BackgroundWorker 启动管道,从而可以捕获 BackgroundWorker 的线程同步上下文。您认为使用 Progress<T> 从管道向 BackgroundWorker 报告,然后由 BackgroundWorker 触发 progresschanged 事件到 UI 是否是更好的选择? - JNYRanger
2
我认为你在这里不需要使用BackgroundWorker。只需在UI线程上创建Progress<T>(它会捕获上下文并在内部使用sc.Post),然后在数据流管道中的任何进展被取得的地方调用它即可。 - noseratio - open to work
1
@Noseratio 谢谢你的建议。我会研究一下这个。 - JNYRanger
1个回答

2
由于 Noseratio 的建议,我重新设计了这个过程,并且成功地让它运行起来。由于`BackgroundWorker`对象并不是必须的,所以我将整个数据流包装在一个异步方法中,并为进度更新提供了各种 `Progress<T>` 参数作为回调函数。为了发布进度,没有需要使用额外的 TPL 块,因为`Progress<T>`的`Report()`方法在现有块内被调用。此外,由于这是一个异步函数,所以代表数据流的任务不会在 UI 线程上运行,而是在线程池线程上运行。最重要的是,要注意`Progress<T>`对象的回调函数在创建它们的线程上运行,因为在构造时它们捕获了当前同步上下文。以下是解决我的问题的示例:
public static async Task ProcessData(IProgress<int> ReadProg, IProgress<int> UploadProg)
{
      var loadBuffer = new BufferBlock<string>();
      var parseBlock = new TransformBlock<string, MyObject>(async s =>
      {
          if(await DoSomething(s))
              ReadProg.Report(1);
          else
              ReadProg.Report(-1);
       });
       ...
       //setup of other blocks
       //link blocks
       //feed data into pipeline by adding data into the head block: loadBuffer
       //await ALL continuation tasks of the blocks
}


然后我在UI中创建了Progress<int>对象,并将它们传递到异步的ProcessData方法中。每当在异步处理方法中调用Process<T>.Report()方法时,UI都会顺利更新。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接