3

考慮以下幾點:TPL Dataflow,我可以查詢一個數據塊是否標記完成但尚未完成?

BufferBlock<int> sourceBlock = new BufferBlock<int>(); 
TransformBlock<int, int> targetBlock = new TransformBlock<int, int>(element => 
    { 
     return element * 2; 
    }); 

sourceBlock.LinkTo(targetBlock, new DataflowLinkOptions { PropagateCompletion = true }); 

//feed some elements into the buffer block 
for(int i = 1; i <= 1000000; i++) 
{ 
    sourceBlock.SendAsync(i); 
} 

sourceBlock.Complete(); 

targetBlock.Completion.ContinueWith(_ => 
    { 
     //notify completion of the target block 
    }); 

targetBlock似乎從來沒有完成,我想原因是,在TransformBlock所有項目「targetBlock」是在outQueue等待,因爲我還沒有聯繫的targetBlock任何其他數據塊。然而,我實際上想要實現的是當(A)targetBlock被通知完成AND(B)輸入隊列爲空時的通知。我不想在乎項目是否仍然位於TransformBlock的輸出隊列中。我怎麼去解決這個問題?獲得我想要查詢sourceBlock的完成狀態並確保targetBlock的InputCount爲零的唯一方法是?我不確定這是否非常穩定(如果sourceBlock中的最後一項已經傳遞給targetBlock,sourceBlock是否真的只被標記爲已完成?)。是否有一種更優雅更有效的方式來實現相同的目標?

編輯:我只是注意到即使是「髒」的方式來檢查完成sourceBlock和inputBlock爲零是不是微不足道的實施。該塊在哪裏坐?它不能在targetBlock內,因爲一旦滿足上面兩個條件,顯然沒有消息在targetBlock內被處理了。同時檢查sourceBlock的完成狀態會導致很多低效率。

+0

爲什麼你需要知道這個? – svick

+0

因爲即使項目保留在outQueue中,一旦targetBlock中的所有項都完成處理,我便完成一個過程。一個原因是該過程的完成,另一個原因是延遲,吞吐量性能的測量。鏈接的下一個數據塊可能需要很長時間才能處理outQueue中的所有剩餘項目 –

+0

爲什麼不直接等待源塊的任務?你不需要附加一個塊,只是源塊的Completion屬性的延續。 – casperOne

回答

1

我相信你不能直接做到這一點。有可能您可以使用反射從某些private字段獲取此信息,但我不建議這樣做。

但是你可以通過創建自定義塊來實現。在Complete()的情況下很簡單:只需創建一個塊,將每個方法轉發到原始塊。除了Complete()之外,它還會記錄它。

在確定所有項目的處理完成時,您可以將您的塊鏈接到中間的BufferBlock。通過這種方式,輸出隊列將快速清空,因此檢查內部塊的Completed會使您對處理完成的時間進行相當精確的測量。這會影響你的測量結果,但希望不會太大。

另一種選擇是在代碼塊的末尾添加一些日誌記錄。這樣,您可以看到最後一個項目的處理何時完成。