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

时间:2014-03-28 21:27:21

标签: c# multithreading user-interface dataflow tpl-dataflow

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

  1. 从文件加载数据
  2. 使用变换块解析记录
  3. 序列化&通过REST将对象上传到服务器
  4. 此处理管道可以自动启动,也可以通过GUI启动。当它从GUI启动时,我想向最终用户提供进度消息。如果我在第1步和第1步之间添加BufferBlock 2,在步骤3之后设置ActionBlock并设置它们在与UI相同的线程上运行的选项,其他块是否仍然使用自己的线程池从UI运行?

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

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

1 个答案:

答案 0 :(得分:1)

感谢Noseratio的建议,我实际上重新设计了这样做的原因,并且能够让它在没有问题的情况下工作。我删除了BackgroundWorker对象,因为它没有必要。相反,我将整个数据流包装在一个异步方法中,该方法将各种Progress<T>参数作为进度更新的回调。由于在预先存在的块中调用Progress<T>的{​​{1}}方法,因此没有使用额外的TPL块来发布进度。此外,由于这是一个异步函数,表示数据流的Task不在UI线程上运行,而是在线程池线程上运行。从中可以看出,Report()对象的回调是在它们创建的线程上运行的,因为在构造过程中它们捕获当前的同步上下文。以下是解决我的问题的一个示例:

Progress<T>


然后在UI中创建了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 } 个对象,并将它们传递给异步Progress<int>方法。每当在异步处理方法中调用ProcessData方法时,UI都会更新而不会出现问题。