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

本文关键字:线程 运行 UI 数据流 TPL | 更新日期: 2023-09-27 17:54:52

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

  1. 从文件加载数据
  2. 使用转换块分析记录
  3. 通过 REST 序列化和上传对象到服务器

此处理管道可以自动启动,也可以通过 GUI 启动。 当它从GUI启动时,我想向最终用户提供进度消息。 如果我在步骤 1 和 2 以及步骤 3 之后的ActionBlock之间添加一个BufferBlock,并设置它们在与 UI 相同的线程上运行的选项,其他块是否仍会使用自己的线程池在 UI 上运行?

我正在查看这篇 MSDN 文章:http://msdn.microsoft.com/en-us/library/hh228605(v=vs.110(.aspx但对于这种行为不是很清楚。 是否可以从管道触发也可以在 UI 线程上运行的事件来完成此操作?

编辑:管道将从 UI 上的 BackgroundWorker 对象启动,而不是直接从 UI 线程启动。

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

多亏了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 都会更新而不会出现问题。