Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
345 views
in Technique[技术] by (71.8m points)

c# - TPL Dataflow, whats the functional difference between Post() and SendAsync()?

I am confused about the difference between sending items through Post() or SendAsync(). My understanding is that in all cases once an item reached the input buffer of a data block, control is returned to the calling context, correct? Then why would I ever need SendAsync? If my assumption is incorrect then I wonder, on the contrary, why anyone would ever use Post() if the whole idea of using data blocks is to establish a concurrent and async environment.

I understand of course the difference technically in that Post() returns a bool whereas SendAsync returns an awaitable Task of bool. But what implications does that have? When would the return of a bool (which I understand is a confirmation whether the item was placed in the queue of the data block or not) ever be delayed? I understand the general idea of the async/await concurrency framework but here it does not make a whole lot sense because other than a bool the results of whatever is done to the passed-in item is never returned to the caller but instead placed in an "out-queue" and either forwarded to linked data blocks or discarded.

And is there any performance difference between the two methods when sending items?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

To see the difference, you need a situation where blocks will postpone their messages. In this case, Post will return false immediately, whereas SendAsync will return a Task that will be completed when the block decides what to do with the message. The Task will have a true result if the message is accepted, and a false result if not.

One example of a postponing situation is a non-greedy join. A simpler example is when you set 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);
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...