2014-03-28 74 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均會更新而不會出現問題。