我正在构建一个数据流管道来执行自然发生的流中的各种处理(主要是 I/O,但也有一些 CPU 处理)。流程目前处于这种基本模式:
- 从文件加载数据
- 使用转换 block 解析记录
- 通过 REST 序列化并上传对象到服务器
此处理管道可以自动启动,也可以通过 GUI 启动。当它从 GUI 启动时,我想向最终用户提供进度消息。如果我在第 1 步和第 2 步之间添加一个 BufferBlock
并在第 3 步之后添加一个 ActionBlock
并将选项设置为在与 UI 相同的线程上运行,其他 block 是否会仍然使用他们自己的线程池运行 UI?
我在看这篇 MSDN 文章:http://msdn.microsoft.com/en-us/library/hh228605(v=vs.110).aspx但对于这种行为还不是很清楚。我是否可以从也可以在 UI 线程上运行的管道中触发一个事件来完成此操作?
编辑:管道将从 UI 上的 BackgroundWorker
对象启动,而不是直接从 UI 线程启动。
最佳答案
多亏了 Noseratio 的建议,我实际上重新设计了它是如何完成的,并且能够让它正常工作。我消除了 BackgroundWorker
对象,因为它不是真正必要的。相反,我将整个数据流包装在一个异步方法中,该方法采用各种 Progress<T>
参数作为进度更新的回调。自 Progress<T>
以来,没有使用额外的 TPL block 来发布进度的 Report()
方法在预先存在的 block 中调用。此外,由于这是一个异步函数,表示数据流的任务不在 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 更新的异步处理方法中调用了方法,没有问题。
关于c# - TPL 数据流 block 在 UI 线程上运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22723495/