32

我對通過Post()或SendAsync()發送項目之間的區別感到困惑。我的理解是,在所有情況下,一旦某個項目到達數據塊的輸入緩衝區,控制就會返回到調用上下文,對不對?那麼爲什麼我需要SendAsync?如果我的假設不正確,相反,如果使用數據塊的整個想法是建立一個併發和異步環境,爲什麼有人會使用Post()。TPL Dataflow,Post()和SendAsync()之間的功能區別是什麼?

我理解當然在技術上的差異在於Post()返回一個bool,而SendAsync返回一個可等候的bool任務。但是這有什麼影響?什麼時候會返回一個bool(我知道是否確認這個項目是否放在數據塊的隊列中)是否會延遲?我理解異步/等待併發框架的一般概念,但在這裏並沒有多少意義,因爲除了bool之外,對傳入的項目執行的任何操作的結果都不會返回給調用者,而是放置在「出隊」並轉發到鏈接的數據塊或丟棄。

發送項目時,兩種方法之間是否存在性能差異?

回答

39

要看到區別,你需要一個塊將推遲他們的消息的情況。在這種情況下,Post將立即返回false,而SendAsync將返回一個Task,當塊決定如何處理該消息時將會完成。如果消息被接受,則Task將具有true結果,如果不是,則結果爲false

推遲情況的一個示例是非貪婪連接。一個簡單的例子是,當你設置BoundedCapacity

[TestMethod] 
public void Post_WhenNotFull_ReturnsTrue() 
{ 
    var block = new BufferBlock<int>(new DataflowBlockOptions {BoundedCapacity = 1}); 

    var result = block.Post(13); 

    Assert.IsTrue(result); 
} 

[TestMethod] 
public void Post_WhenFull_ReturnsFalse() 
{ 
    var block = new BufferBlock<int>(new DataflowBlockOptions { BoundedCapacity = 1 }); 
    block.Post(13); 

    var result = block.Post(13); 

    Assert.IsFalse(result); 
} 

[TestMethod] 
public void SendAsync_WhenNotFull_ReturnsCompleteTask() 
{ 
    // This is an implementation detail; technically, SendAsync could return a task that would complete "quickly" instead of already being completed. 
    var block = new BufferBlock<int>(new DataflowBlockOptions { BoundedCapacity = 1 }); 

    var result = block.SendAsync(13); 

    Assert.IsTrue(result.IsCompleted); 
} 

[TestMethod] 
public void SendAsync_WhenFull_ReturnsIncompleteTask() 
{ 
    var block = new BufferBlock<int>(new DataflowBlockOptions { BoundedCapacity = 1 }); 
    block.Post(13); 

    var result = block.SendAsync(13); 

    Assert.IsFalse(result.IsCompleted); 
} 

[TestMethod] 
public async Task SendAsync_BecomesNotFull_CompletesTaskWithTrueResult() 
{ 
    var block = new BufferBlock<int>(new DataflowBlockOptions { BoundedCapacity = 1 }); 
    block.Post(13); 
    var task = block.SendAsync(13); 

    block.Receive(); 

    var result = await task; 
    Assert.IsTrue(result); 
} 

[TestMethod] 
public async Task SendAsync_BecomesDecliningPermanently_CompletesTaskWithFalseResult() 
{ 
    var block = new BufferBlock<int>(new DataflowBlockOptions { BoundedCapacity = 1 }); 
    block.Post(13); 
    var task = block.SendAsync(13); 

    block.Complete(); 

    var result = await task; 
    Assert.IsFalse(result); 
} 
+0

好的,但是給出你的解釋,那麼'Task '背後的邏輯是什麼?如果由於推遲而無法立即提交,但任務稍後完成,那麼bool是真的還是假的區別? –

+1

該塊可能最終決定拒絕該消息(例如,如果您完成了該塊),在這種情況下,該任務的結果將爲「假」。查看更新的答案。 –

+0

太棒了,這現在完全有意義,這種可能性完全滑落了我的想法。非常感謝。 –

7

該文件使這個合理清晰,國際海事組織。特別是,對於Post

此方法將返回一旦目標塊已決定接受或拒絕該項目,但除非目標塊的特殊語義另有規定,否則它不會等待該項目的實際被處理。

和:

對於支持推遲要約的消息,或者選擇那些在他們的Post實施做更多的處理塊目標塊,可以考慮使用SendAsync,這將立即返回,將使目標推遲發佈的消息,然後在SendAsync返回後消耗它。

換句話說,雖然兩者都是異步相對於處理消息,SendAsync允許目標塊,以決定是否要接受消息異步過。

聽起來像SendAsync是一種「更加異步」的方法,一般可能會被鼓勵。 不是對我來說很清楚爲什麼這兩個都是必需的,因爲它肯定聽起來像Post大致等同於使用SendAsync,然後等待結果。

+0

感謝,它使人們更清楚一點,雖然你的最後一句話總結了我剩下的混亂。從我自己的測試中,當一個數據塊拒絕接受一條消息時,我沒有發現使用SendAsync方法比Post方式有什麼優勢,但是當數據塊指示它稍後接受消息時,兩者都不會嘗試重新傳遞消息。 (如果消息被拒絕,則立即返回,如果消息被接受,則兩者立即返回)。因爲「接受」消息的語義重新發布對SendAsync仍然是模糊的。 –

+0

我想我只是不明白在新的傳遞消息的「接受/拒絕」機制中可能會引入多少延遲。到目前爲止,我從來沒有看到消息在隊列輸入隊列/拒絕隊列中的傳遞和到達之間有任何可測量的延遲。但是,無論如何要把焦點放在問題的「接受/拒絕」部分上。 –

+3

@Freddy:當然 - 不同的是當一個區塊推遲*接受/拒絕決定。當然,也許你使用的目標塊從來沒有這樣做。 –

相關問題