2014-03-28 25 views
3

我正在构建一个数据流管道,以执行处于自然发生流程中的各种处理(主要是I/O,但某些CPU处理)。流量是目前在这个基本格局:从文件 在UI线程上运行的TPL数据流块

  • 解析记录使用通过REST
  • 该处理管道就可以开始变换块

  • 序列化&上传对象到服务器

    1. 加载数据自动或通过GUI。对于从GUI启动时,我想向最终用户提供进度消息。如果我在步骤3之后在步骤1 & 2和ActionBlock之间添加BufferBlock,并为它们设置了与UI相同的线程运行的选项,其他块是否仍会使用自己的线程池运行UI?

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

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

  • +0

    您是否在使用'DataflowBlockOptions.TaskScheduler'使其运行UI线程?一段代码会有帮助。 – Noseratio

    +0

    @Noseratio这更多的是一个理论问题。我仍然计划这个功能。截至目前,它没有报告进展情况。使用'DataflowBlockOptions.TaskScheduler'是我如何告诉那些特定的块在UI线程上运行。 – JNYRanger

    +1

    我会使用'Progress '模式,并没有诉诸UI线程TaskScheduler。 – 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<int>对象,并通过他们到异步ProcessData方法。无论何时在异步处理方法中调用Process<T>.Report()方法,UI均会更新而不会出现问题。