TPL Dataflow,Post()和SendAsync()之间的功能区别是什么?

Mat*_*olf 46 c# concurrency message-passing task-parallel-library tpl-dataflow

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

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

发送项目时两种方法之间是否存在性能差异?

Ste*_*ary 55

要查看差异,您需要一个块将推迟其消息的情况.在这种情况下,Postfalse立即返回,而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);
}
Run Code Online (Sandbox Code Playgroud)

  • 那么这是否意味着每个人都应该*总是*使用SendAsync,除非他们可以删除邮件? (5认同)
  • 是,是,并不完全.如果块推迟消息,"SendAsync"将构造一个"消息持有者",它将保留消息,直到块接收或拒绝它."任务"实际上是消息持有者的一部分.此外,在处理延期时,目标块具有数据结构以跟踪其推迟的消息源(其将包括"消息持有者"). (3认同)
  • `Post`立即返回; 所以如果块推迟,它将返回`false`."邮政"没有"信息持有者".有一个很棒的文档[实现自定义TPL数据流块的指南](http://download.microsoft.com/download/1/6/1/1615555D-287C-4159-8491-8E5644C43CBA/Guide%20to%20Implementing%20Custom% 20TPL%20Dataflow%20Blocks.pdf)更深入地介绍了Dataflow块的实际工作方式. (3认同)

Jon*_*eet 15

该文件使IMO明确清楚.尤其适用于Post:

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

和:

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

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

这听起来像是SendAsync一种通常"更加异步"的方法,而且可能是一般的鼓励方法.什么不是很清楚,我就是两者都需要,因为它肯定听起来就像Post是大致等同于使用SendAsync,然后就等待结果.

  • @Freddy:当然 - 但区别在于阻止*推迟*接受/拒绝决定.当然,也许您正在使用的目标块永远不会这样做. (4认同)