59

我对通过 Post() 或 SendAsync() 发送项目之间的区别感到困惑。我的理解是,在所有情况下,一旦项目到达数据块的输入缓冲区,控制权就会返回到调用上下文,对吗?那我为什么需要 SendAsync 呢?如果我的假设不正确,那么我想知道,相反,如果使用数据块的整个想法是建立一个并发和异步环境,为什么有人会使用 Post()。

我当然理解技术上的区别,即 Post() 返回一个 bool 而 SendAsync 返回一个可等待的 bool 任务。但这有什么影响?什么时候会延迟返回布尔值(我的理解是确认该项目是否已放入数据块的队列中)?我理解 async/await 并发框架的一般概念,但在这里它没有多大意义,因为除了 bool 之外,对传入项目所做的任何事情的结果都不会返回给调用者,而是放在一个“out-queue”并转发到链接的数据块或丢弃。

发送物品时这两种方法之间有什么性能差异吗?

4

2 回答 2

68

要查看差异,您需要一个块将推迟其消息的情况。在这种情况下,Postfalse立即返回,而将在块决定如何处理消息时SendAsync返回将完成的 a 。Task如果消息被接受,Task则将有结果,如果不接受,则将有结果。truefalse

延迟情况的一个示例是非贪婪连接。一个更简单的例子是当你设置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);
}
于 2012-11-28T13:17:35.540 回答
20

IMO,该文档使这一点相当清楚。特别是,对于Post

一旦目标块决定接受或拒绝该项目,此方法将返回,但除非目标块的特殊语义另有规定,否则它不会等待项目实际被处理。

和:

对于支持延迟提供消息的目标块,或者对于可能在其Post实现中进行更多处理的块,请考虑使用SendAsync,它将立即返回并使目标能够推迟发布的消息并在SendAsync返回后稍后使用它。

换句话说,虽然两者在处理消息方面都是异步的,但也SendAsync允许目标块决定是否异步接受消息。

这听起来像是SendAsync一种通常“更异步”的方法,并且通常可能受到鼓励。我不清楚为什么两者都是必需的,因为这听起来肯定Post大致相当于使用SendAsync然后等待结果。正如评论中所指出的,有一个显着的区别:如果缓冲区已满,Post将立即拒绝,而SendAsync不会。

于 2012-11-28T07:09:50.227 回答