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:当然 - 不同的是当一个区块推迟*接受/拒绝决定。当然,也许你使用的目标块从来没有这样做。 –

相关问题