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

Posted

技术标签:

【中文标题】在 UI 线程上运行的 TPL 数据流块【英文标题】:TPL Dataflow Blocks Running On UI Thread 【发布时间】:2014-05-08 13:03:52 【问题描述】:

我正在构建一个数据流管道来执行自然流中的各种处理(主要是 I/O,但也有一些 CPU 处理)。流程目前处于这种基本模式:

    从文件中加载数据 使用转换块解析记录 通过 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 这更像是一个理论问题。我还在计划这个功能。截至目前,它还没有报告进度。使用DataflowBlockOptions.TaskScheduler 是我要告诉那些特定块在 UI 线程上运行的方式。 我会使用Progress<T> 模式,而不是使用 UI 线程 TaskScheduler。 我认为你在这里不需要BackgroundWorker。只需在 UI 线程上创建 Progress<T>(它确实捕获 s. 上下文并在内部使用 sc.Post)。然后在取得进展的任何地方从您的 Dataflow 管道中调用它。 @Noseratio 感谢您的建议。我会调查一下。 【参考方案1】:

多亏了 Noseratio 的建议,我实际上重新设计了它是如何完成的,并且能够让它毫无问题地工作。我删除了 BackgroundWorker 对象,因为它并不是真正需要的。相反,我将整个数据流包装在一个异步方法中,该方法将各种Progress<T> 参数作为进度更新的回调。由于Progress<T>Report() 方法在预先存在的块中被调用,因此没有使用额外的TPL 块来发布进度。此外,由于这是一个异步函数,表示数据流的任务不在 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&lt;int&gt; 对象并将它们传递给异步 ProcessData 方法。每当在异步处理方法中调用 Process&lt;T&gt;.Report() 方法时,UI 都会毫无问题地更新。

【讨论】:

以上是关于在 UI 线程上运行的 TPL 数据流块的主要内容,如果未能解决你的问题,请参考以下文章

TPL 数据流块消耗所有可用内存

TPL 数据流块永远不会在 PropagateCompletion 上完成

Windows 模拟和 TPL

TPL 可以在多个线程上运行任务吗?

TPL Dataflow,数据块收到第一项时的通知

TPL 数据流在运行时中断 LinkTo()